From 7656d8f20ca8da0ba2871bfcf660acd3801f70e9 Mon Sep 17 00:00:00 2001 From: Ilya Putilin Date: Thu, 26 Dec 2024 12:24:02 +0700 Subject: [PATCH] Add the ability to import multiple files --- src/core/core.pro | 2 + .../content/import/import_manager.cpp | 174 ++-- src/core/ui/import/file_name_delegate.cpp | 172 ++++ src/core/ui/import/file_name_delegate.h | 25 + src/core/ui/import/import_dialog.cpp | 809 +++++++++++++----- src/core/ui/import/import_dialog.h | 11 +- src/core/ui/menu_view.cpp | 2 +- .../import/abstract_document_importer.cpp | 12 +- .../import/abstract_document_importer.h | 6 +- .../import/abstract_fountain_importer.cpp | 8 +- .../import/abstract_fountain_importer.h | 2 +- .../business_layer/import/abstract_importer.h | 2 +- .../audioplay/abstract_audioplay_importer.h | 2 +- .../audioplay/audioplay_fountain_importer.cpp | 8 +- .../audioplay/audioplay_fountain_importer.h | 2 +- .../comic_book/abstract_comic_book_importer.h | 2 +- .../comic_book_fountain_importer.cpp | 8 +- .../comic_book/comic_book_fountain_importer.h | 2 +- .../import/novel/abstract_novel_importer.h | 2 +- .../import/novel/novel_markdown_importer.cpp | 6 +- .../import/novel/novel_markdown_importer.h | 2 +- .../screenplay/abstract_screenplay_importer.h | 2 +- .../screenplay/screenplay_celtx_importer.cpp | 16 +- .../screenplay/screenplay_celtx_importer.h | 4 +- .../screenplay/screenplay_docx_importer.cpp | 14 +- .../screenplay/screenplay_docx_importer.h | 4 +- .../screenplay/screenplay_fdx_importer.cpp | 16 +- .../screenplay/screenplay_fdx_importer.h | 4 +- .../screenplay_fountain_importer.cpp | 10 +- .../screenplay/screenplay_fountain_importer.h | 2 +- .../screenplay_kit_scenarist_importer.cpp | 20 +- .../screenplay_kit_scenarist_importer.h | 4 +- .../screenplay/screenplay_pdf_importer.cpp | 14 +- .../screenplay/screenplay_pdf_importer.h | 4 +- .../screenplay/screenplay_trelby_importer.cpp | 16 +- .../screenplay/screenplay_trelby_importer.h | 4 +- .../stageplay/abstract_stageplay_importer.h | 2 +- .../stageplay/stageplay_fountain_importer.cpp | 8 +- .../stageplay/stageplay_fountain_importer.h | 2 +- 39 files changed, 1038 insertions(+), 367 deletions(-) create mode 100644 src/core/ui/import/file_name_delegate.cpp create mode 100644 src/core/ui/import/file_name_delegate.h diff --git a/src/core/core.pro b/src/core/core.pro index 867b47870..a22e04247 100644 --- a/src/core/core.pro +++ b/src/core/core.pro @@ -100,6 +100,7 @@ SOURCES += \ ui/export/script_export_dialog.cpp \ ui/export/simple_text_export_dialog.cpp \ ui/export/stageplay_export_dialog.cpp \ + ui/import/file_name_delegate.cpp \ ui/import/import_dialog.cpp \ ui/menu_view.cpp \ ui/notifications/credits_view.cpp \ @@ -195,6 +196,7 @@ HEADERS += \ ui/export/script_export_dialog.h \ ui/export/simple_text_export_dialog.h \ ui/export/stageplay_export_dialog.h \ + ui/import/file_name_delegate.h \ ui/import/import_dialog.h \ ui/menu_view.h \ ui/notifications/credits_view.h \ diff --git a/src/core/management_layer/content/import/import_manager.cpp b/src/core/management_layer/content/import/import_manager.cpp index 7e558e10f..fc9ed6c46 100644 --- a/src/core/management_layer/content/import/import_manager.cpp +++ b/src/core/management_layer/content/import/import_manager.cpp @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -30,18 +32,18 @@ class ImportManager::Implementation explicit Implementation(ImportManager* _parent, QWidget* _topLevelWidget); /** - * @brief Показать диалог импорта для заданного файла + * @brief Показать диалог импорта для заданных файлов */ - void showImportDialogFor(const QString& _path); + void showImportDialogFor(const QStringList& _paths); /** * @brief Импортировать данные документа из заданного файла */ - void importAudioplay(const BusinessLayer::ImportOptions& _options); - void importComicBook(const BusinessLayer::ImportOptions& _options); - void importNovel(const BusinessLayer::ImportOptions& _options); - void importScreenplay(const BusinessLayer::ScreenplayImportOptions& _options); - void importStageplay(const BusinessLayer::ImportOptions& _options); + void importAudioplay(const BusinessLayer::ImportOptions* _options); + void importComicBook(const BusinessLayer::ImportOptions* _options); + void importNovel(const BusinessLayer::ImportOptions* _options); + void importScreenplay(const BusinessLayer::ScreenplayImportOptions* _options); + void importStageplay(const BusinessLayer::ImportOptions* _options); // // Данные @@ -60,54 +62,67 @@ ImportManager::Implementation::Implementation(ImportManager* _parent, QWidget* _ { } -void ImportManager::Implementation::showImportDialogFor(const QString& _path) +void ImportManager::Implementation::showImportDialogFor(const QStringList& _paths) { // // Формат MS DOC не поддерживается, он отображается только для того, чтобы пользователи // не теряли свои файлы // - if (_path.toLower().endsWith(ExtensionHelper::msOfficeBinary())) { + QStringList docFiles; + QStringList filesToImport; + for (const auto& path : _paths) { + if (path.toLower().endsWith(ExtensionHelper::msOfficeBinary())) { + docFiles.append(path); + } else { + filesToImport.append(path); + } + } + + if (!docFiles.isEmpty() && filesToImport.isEmpty()) { StandardDialog::information(topLevelWidget, tr("File format not supported"), tr("Importing from DOC files is not supported. You need to " "save the file in DOCX format and repeat the import.")); return; } + // + // Создаем диалог импорта + // if (importDialog == nullptr) { - importDialog = new Ui::ImportDialog(_path, topLevelWidget); + importDialog = new Ui::ImportDialog(filesToImport, topLevelWidget); connect(importDialog, &Ui::ImportDialog::importRequested, importDialog, [this] { - const auto importOptions = importDialog->importOptions(); - switch (importOptions.documentType) { - default: - case Domain::DocumentObjectType::Undefined: { - break; - } - case Domain::DocumentObjectType::Audioplay: { - importDialog->hideDialog(); - importAudioplay(importOptions); - break; - } - case Domain::DocumentObjectType::ComicBook: { - importDialog->hideDialog(); - importComicBook(importOptions); - break; - } - case Domain::DocumentObjectType::Novel: { - importDialog->hideDialog(); - importNovel(importOptions); - break; - } - case Domain::DocumentObjectType::Screenplay: { - const auto screenplayImportOptions = importDialog->screenplayImportOptions(); - importDialog->hideDialog(); - importScreenplay(screenplayImportOptions); - break; - } - case Domain::DocumentObjectType::Stageplay: { - importDialog->hideDialog(); - importStageplay(importOptions); - break; - } + const auto optionsList = importDialog->importOptions(); + importDialog->hideDialog(); + for (const auto& importOptions : optionsList) { + switch (importOptions->documentType) { + default: + case Domain::DocumentObjectType::Undefined: { + break; + } + case Domain::DocumentObjectType::Audioplay: { + importAudioplay(importOptions.get()); + break; + } + case Domain::DocumentObjectType::ComicBook: { + importComicBook(importOptions.get()); + break; + } + case Domain::DocumentObjectType::Novel: { + importNovel(importOptions.get()); + break; + } + case Domain::DocumentObjectType::Screenplay: { + const auto screenplayImportOptions + = static_cast( + importOptions.get()); + importScreenplay(screenplayImportOptions); + break; + } + case Domain::DocumentObjectType::Stageplay: { + importStageplay(importOptions.get()); + break; + } + } } }); connect(importDialog, &Ui::ImportDialog::canceled, importDialog, @@ -118,17 +133,42 @@ void ImportManager::Implementation::showImportDialogFor(const QString& _path) }); } - importDialog->showDialog(); + // + // Прежде чем показать диалог импорта, выведем предупреждение, если нужно + // + if (!docFiles.isEmpty() && !filesToImport.isEmpty()) { + QString filesList; + for (const auto& file : docFiles) { + QFileInfo fileInfo(file); + filesList += fileInfo.fileName() + "\n"; + } + QString title("File format not supported"); + QString text(tr("Importing from DOC files is not supported. You need to " + "save the file in DOCX format and repeat the import.\n\nThe " + "following files will not be imported:\n") + + filesList); + auto dialog = new Dialog(topLevelWidget); + dialog->setContentMaximumWidth(Ui::DesignSystem::dialog().maximumWidth()); + dialog->showDialog(title, text, + { { 0, StandardDialog::generateOkTerm(), Dialog::RejectButton } }); + QObject::connect(dialog, &Dialog::finished, dialog, [this, dialog]() { + dialog->hideDialog(); + importDialog->showDialog(); + }); + QObject::connect(dialog, &Dialog::disappeared, dialog, &Dialog::deleteLater); + } else { + importDialog->showDialog(); + } } -void ImportManager::Implementation::importAudioplay(const BusinessLayer::ImportOptions& _options) +void ImportManager::Implementation::importAudioplay(const BusinessLayer::ImportOptions* _options) { // // Определим нужный импортер // QScopedPointer importer; { - const auto importFilePath = _options.filePath.toLower(); + const auto importFilePath = _options->filePath.toLower(); if (importFilePath.endsWith(ExtensionHelper::fountain()) || importFilePath.endsWith(ExtensionHelper::plainText())) { importer.reset(new BusinessLayer::AudioplayFountainImporter); @@ -149,18 +189,18 @@ void ImportManager::Implementation::importAudioplay(const BusinessLayer::ImportO const auto audioplay = importer->importAudioplay(_options); const auto audioplayName = !audioplay.name.isEmpty() ? audioplay.name - : QFileInfo(_options.filePath).completeBaseName(); + : QFileInfo(_options->filePath).completeBaseName(); emit q->audioplayImported(audioplayName, audioplay.titlePage, audioplay.text); } -void ImportManager::Implementation::importComicBook(const BusinessLayer::ImportOptions& _options) +void ImportManager::Implementation::importComicBook(const BusinessLayer::ImportOptions* _options) { // // Определим нужный импортер // QScopedPointer importer; { - const auto importFilePath = _options.filePath.toLower(); + const auto importFilePath = _options->filePath.toLower(); if (importFilePath.endsWith(ExtensionHelper::fountain()) || importFilePath.endsWith(ExtensionHelper::plainText())) { importer.reset(new BusinessLayer::ComicBookFountainImporter); @@ -181,18 +221,18 @@ void ImportManager::Implementation::importComicBook(const BusinessLayer::ImportO const auto comicbook = importer->importComicBook(_options); const auto comicbookName = !comicbook.name.isEmpty() ? comicbook.name - : QFileInfo(_options.filePath).completeBaseName(); + : QFileInfo(_options->filePath).completeBaseName(); emit q->comicbookImported(comicbookName, comicbook.titlePage, comicbook.text); } -void ImportManager::Implementation::importNovel(const BusinessLayer::ImportOptions& _options) +void ImportManager::Implementation::importNovel(const BusinessLayer::ImportOptions* _options) { // // Определим нужный импортер // QScopedPointer importer; { - const auto importFilePath = _options.filePath.toLower(); + const auto importFilePath = _options->filePath.toLower(); if (importFilePath.endsWith(ExtensionHelper::markdown()) || importFilePath.endsWith(ExtensionHelper::plainText())) { importer.reset(new BusinessLayer::NovelMarkdownImporter); @@ -204,19 +244,19 @@ void ImportManager::Implementation::importNovel(const BusinessLayer::ImportOptio // const auto novel = importer->importNovel(_options); const auto novelName - = !novel.name.isEmpty() ? novel.name : QFileInfo(_options.filePath).completeBaseName(); + = !novel.name.isEmpty() ? novel.name : QFileInfo(_options->filePath).completeBaseName(); emit q->novelImported(novelName, novel.text); } void ImportManager::Implementation::importScreenplay( - const BusinessLayer::ScreenplayImportOptions& _importOptions) + const BusinessLayer::ScreenplayImportOptions* _importOptions) { // // Определим нужный импортер // QScopedPointer importer; { - const auto importFilePath = _importOptions.filePath.toLower(); + const auto importFilePath = _importOptions->filePath.toLower(); if (importFilePath.endsWith(ExtensionHelper::kitScenarist())) { importer.reset(new BusinessLayer::ScreenplayKitScenaristImporter); } else if (importFilePath.endsWith(ExtensionHelper::finalDraft()) @@ -258,20 +298,20 @@ void ImportManager::Implementation::importScreenplay( for (const auto& screenplay : screenplays) { const auto screenplayName = !screenplay.name.isEmpty() ? screenplay.name - : QFileInfo(_importOptions.filePath).completeBaseName(); + : QFileInfo(_importOptions->filePath).completeBaseName(); emit q->screenplayImported(screenplayName, screenplay.titlePage, screenplay.synopsis, screenplay.treatment, screenplay.text); } } -void ImportManager::Implementation::importStageplay(const BusinessLayer::ImportOptions& _options) +void ImportManager::Implementation::importStageplay(const BusinessLayer::ImportOptions* _options) { // // Определим нужный импортер // QScopedPointer importer; { - const auto importFilePath = _options.filePath.toLower(); + const auto importFilePath = _options->filePath.toLower(); if (importFilePath.endsWith(ExtensionHelper::fountain()) || importFilePath.endsWith(ExtensionHelper::plainText())) { importer.reset(new BusinessLayer::StageplayFountainImporter); @@ -292,7 +332,7 @@ void ImportManager::Implementation::importStageplay(const BusinessLayer::ImportO const auto stageplay = importer->importStageplay(_options); const auto stageplayName = !stageplay.name.isEmpty() ? stageplay.name - : QFileInfo(_options.filePath).completeBaseName(); + : QFileInfo(_options->filePath).completeBaseName(); emit q->stageplayImported(stageplayName, stageplay.titlePage, stageplay.text); } @@ -317,24 +357,24 @@ void ImportManager::import() // const auto projectImportFolder = settingsValue(DataStorageLayer::kProjectImportFolderKey).toString(); - const auto importFilePath - = QFileDialog::getOpenFileName(d->topLevelWidget, tr("Choose the file to import"), - projectImportFolder, DialogHelper::filtersForImport()); - if (importFilePath.isEmpty()) { + const auto importFilePaths + = QFileDialog::getOpenFileNames(d->topLevelWidget, tr("Choose files to import"), + projectImportFolder, DialogHelper::filtersForImport()); + if (importFilePaths.isEmpty()) { return; } // - // Если файл был выбран + // Если файлы были выбраны // // ... обновим папку, откуда в следующий раз он предположительно опять будет импортировать // проекты // - setSettingsValue(DataStorageLayer::kProjectImportFolderKey, importFilePath); + setSettingsValue(DataStorageLayer::kProjectImportFolderKey, importFilePaths.last()); // // ... и переходим к подготовке импорта // - d->showImportDialogFor(importFilePath); + d->showImportDialogFor(importFilePaths); } void ImportManager::importScreenplay(const QString& _filePath, bool _importDocuments) @@ -345,7 +385,7 @@ void ImportManager::importScreenplay(const QString& _filePath, bool _importDocum options.importCharacters = _importDocuments; options.importLocations = _importDocuments; options.importResearch = _importDocuments; - d->importScreenplay(options); + d->importScreenplay(&options); } void ImportManager::importNovel(const QString& _filePath) @@ -353,7 +393,7 @@ void ImportManager::importNovel(const QString& _filePath) BusinessLayer::ImportOptions options; options.filePath = _filePath; options.documentType = Domain::DocumentObjectType::Novel; - d->importNovel(options); + d->importNovel(&options); } } // namespace ManagementLayer diff --git a/src/core/ui/import/file_name_delegate.cpp b/src/core/ui/import/file_name_delegate.cpp new file mode 100644 index 000000000..f2d4b4be0 --- /dev/null +++ b/src/core/ui/import/file_name_delegate.cpp @@ -0,0 +1,172 @@ +#include "file_name_delegate.h" + +#include "import_dialog.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace Ui { + +FileNameDelegate::FileNameDelegate(QObject* _parent) + : QStyledItemDelegate(_parent) +{ +} + +FileNameDelegate::~FileNameDelegate() = default; + +void FileNameDelegate::paint(QPainter* _painter, const QStyleOptionViewItem& _option, + const QModelIndex& _index) const +{ + // + // Получим настройки стиля + // + QStyleOptionViewItem opt = _option; + initStyleOption(&opt, _index); + + // + // Рисуем ручками + // + _painter->setRenderHint(QPainter::Antialiasing, true); + + auto backgroundColor = _option.palette.color(QPalette::Base); + auto textColor = _option.palette.color(QPalette::Text); + auto fileNameTextColor = _option.palette.color(QPalette::Text); + const auto isLeftToRight = QLocale().textDirection() == Qt::LeftToRight; + + // + // ... фон + // + const QRectF backgroundRect = _option.rect; + if (_option.state.testFlag(QStyle::State_Selected)) { + // + // ... для выделенных элементов + // + backgroundColor = _option.palette.color(QPalette::Highlight); + textColor = _option.palette.color(QPalette::HighlightedText); + } else if (_option.state.testFlag(QStyle::State_MouseOver)) { + // + // ... для элементов на которые наведена мышь + // + backgroundColor = _option.palette.color(QPalette::AlternateBase); + } else { + // + // ... для остальных элементов + // + textColor.setAlphaF(DesignSystem::inactiveTextOpacity()); + } + _painter->fillRect(backgroundRect, backgroundColor); + + // + // ... иконка + // + _painter->setPen(textColor); + QRectF iconRect; + if (isLeftToRight) { + iconRect = QRectF( + QPointF( + std::max(backgroundRect.left(), DesignSystem::treeOneLineItem().margins().left()), + backgroundRect.top()), + QSizeF(DesignSystem::treeOneLineItem().iconSize().width(), backgroundRect.height())); + } else { + iconRect = QRectF( + QPointF(backgroundRect.right() - DesignSystem::treeOneLineItem().iconSize().width(), + backgroundRect.top()), + QSizeF(DesignSystem::treeOneLineItem().iconSize().width(), backgroundRect.height())); + } + _painter->setFont(DesignSystem::font().iconsMid()); + _painter->drawText(iconRect, Qt::AlignLeft | Qt::AlignVCenter, u8"\U000F0214"); + + // + // ... имя файла + // + _painter->setPen(fileNameTextColor); + _painter->setFont(DesignSystem::font().subtitle2()); + qreal fileNameLeft = 0.0; + qreal fileNameWidth = 0.0; + if (isLeftToRight) { + fileNameLeft = iconRect.right() + DesignSystem::treeOneLineItem().spacing(); + fileNameWidth = backgroundRect.right() - DesignSystem::treeOneLineItem().margins().right() + - fileNameLeft - DesignSystem::treeOneLineItem().spacing(); + } else { + fileNameLeft = backgroundRect.left() + DesignSystem::treeOneLineItem().margins().left(); + fileNameWidth = iconRect.left() - fileNameLeft - DesignSystem::treeOneLineItem().spacing(); + } + const QRectF fileNameRect( + QPointF(fileNameLeft, + backgroundRect.top() + DesignSystem::treeOneLineItem().margins().top()), + QSizeF(fileNameWidth, DesignSystem::treeOneLineItem().contentHeight())); + + QString filePath = _index.data().toString(); + QFileInfo fileInfo(filePath); + auto fileName = fileInfo.fileName(); + fileName = _painter->fontMetrics().elidedText(fileName, Qt::ElideRight, + static_cast(fileNameRect.width())); + _painter->drawText(fileNameRect, Qt::AlignLeft | Qt::AlignVCenter, fileName); + + // + // ... текст под именем файла (в какой тип будет импортироваться) + // + if (!_index.data(ImportDialog::ImportEnabledRole).toBool()) { + textColor = QColor(Qt::red); + } + _painter->setPen(textColor); + auto underNameText = _index.data(ImportDialog::ImportTypeRole).toString(); + if (underNameText.isEmpty()) { + return; + } + QRectF textRect; + _painter->setFont(DesignSystem::font().body2()); + if (isLeftToRight) { + const qreal textLeft = iconRect.right() + DesignSystem::treeOneLineItem().spacing(); + const qreal textWidth + = backgroundRect.right() - textLeft - DesignSystem::treeOneLineItem().margins().right(); + textRect + = QRectF(QPointF(textLeft, fileNameRect.bottom() + DesignSystem::compactLayout().px8()), + QSizeF(textWidth, TextHelper::fineLineSpacing(_painter->font()))); + } else { + const qreal textLeft + = backgroundRect.left() + DesignSystem::treeOneLineItem().margins().left(); + const qreal textWidth = iconRect.left() - textLeft; + textRect + = QRectF(QPointF(textLeft, fileNameRect.bottom() + DesignSystem::compactLayout().px8()), + QSizeF(textWidth, TextHelper::fineLineSpacing(_painter->font()))); + } + underNameText = TextHelper::elidedText(underNameText, DesignSystem::font().body2(), textRect); + _painter->drawText(textRect, Qt::TextWordWrap, underNameText); +} + +QSize FileNameDelegate::sizeHint(const QStyleOptionViewItem& _option, + const QModelIndex& _index) const +{ + if (_option.widget == nullptr) { + return QStyledItemDelegate::sizeHint(_option, _index); + } + + // + // Ширина + // + int width = _option.widget->width(); + if (const QAbstractItemView* view = qobject_cast(_option.widget)) { + width = view->viewport()->width(); + } + width -= DesignSystem::layout().px8() + DesignSystem::layout().px16() + + DesignSystem::layout().px16(); + + // + // Высота + // + int height = DesignSystem::treeOneLineItem().height() + DesignSystem::compactLayout().px8() + + TextHelper::fineLineSpacing(DesignSystem::font().body2()); + + return { width, height }; +} + +} // namespace Ui diff --git a/src/core/ui/import/file_name_delegate.h b/src/core/ui/import/file_name_delegate.h new file mode 100644 index 000000000..fc41859a3 --- /dev/null +++ b/src/core/ui/import/file_name_delegate.h @@ -0,0 +1,25 @@ +#pragma once + +#include + + +namespace Ui { + +/** + * @brief Делегат отрисовки имен файлов в списке на импорт + */ +class FileNameDelegate : public QStyledItemDelegate +{ +public: + explicit FileNameDelegate(QObject* _parent = nullptr); + ~FileNameDelegate() override; + + /** + * @brief Реализуем собственную отрисовку + */ + void paint(QPainter* _painter, const QStyleOptionViewItem& _option, + const QModelIndex& _index) const override; + QSize sizeHint(const QStyleOptionViewItem& _option, const QModelIndex& _index) const override; +}; + +} // namespace Ui diff --git a/src/core/ui/import/import_dialog.cpp b/src/core/ui/import/import_dialog.cpp index e5c19870c..1fb3bab21 100644 --- a/src/core/ui/import/import_dialog.cpp +++ b/src/core/ui/import/import_dialog.cpp @@ -2,16 +2,21 @@ #include #include +#include #include #include #include #include +#include +#include #include +#include #include #include #include #include +#include #include @@ -19,37 +24,170 @@ namespace Ui { namespace { const QString kGroupKey = "widgets/import-dialog/"; -const QString kDocumentType = kGroupKey + "document-type"; -const QString kImportCharacters = kGroupKey + "import-characters"; -const QString kImportLocations = kGroupKey + "import-locations"; -const QString kImportResearch = kGroupKey + "import-research"; -const QString kImportText = kGroupKey + "import-text"; -const QString kKeepSceneNumbers = kGroupKey + "keep-scene-numbers"; +const QString kDocumentType = "document-type"; +const QString kImportCharacters = "import-characters"; +const QString kImportLocations = "import-locations"; +const QString kImportResearch = "import-research"; +const QString kImportText = "import-text"; +const QString kKeepSceneNumbers = "keep-scene-numbers"; + +QString settingsKey(const QString& _filePath, const QString& _parameter) +{ + return QString("%1/%2/%3").arg(kGroupKey, _filePath, _parameter); +} + +const QVector> kDocumentTypes{ + { + Domain::DocumentObjectType::Audioplay, + QApplication::translate("ImportDialog", "Audioplay"), + }, + { + Domain::DocumentObjectType::ComicBook, + QApplication::translate("ImportDialog", "Comic Book"), + }, + { + Domain::DocumentObjectType::Novel, + QApplication::translate("ImportDialog", "Novel"), + }, + { + Domain::DocumentObjectType::Screenplay, + QApplication::translate("ImportDialog", "Screenplay"), + }, + { + Domain::DocumentObjectType::Stageplay, + QApplication::translate("ImportDialog", "Stageplay"), + }, +}; + +QString typeToString(const Domain::DocumentObjectType& _type) +{ + for (const auto& type : kDocumentTypes) { + if (type.first == _type) { + return type.second; + } + } + return ""; +} + +Domain::DocumentObjectType stringToType(const QString& _type) +{ + for (const auto& type : kDocumentTypes) { + if (type.second == _type) { + return type.first; + } + } + return Domain::DocumentObjectType::Undefined; +} + +QVector importTypesForFile(const QString& _path) +{ + auto fileIs = [filePath = _path.toLower()](const QString& _extension) { + return filePath.endsWith(_extension); + }; + + // + // Бинарные форматы + // + if (fileIs(ExtensionHelper::msOfficeOpenXml()) || fileIs(ExtensionHelper::openDocumentXml())) { + return { Domain::DocumentObjectType::Screenplay }; + } else if (fileIs(ExtensionHelper::pdf())) { + return { Domain::DocumentObjectType::Screenplay }; + } + // + // Текстовые форматы + // + else if (fileIs(ExtensionHelper::fountain())) { + return { + Domain::DocumentObjectType::Audioplay, + Domain::DocumentObjectType::ComicBook, + Domain::DocumentObjectType::Screenplay, + Domain::DocumentObjectType::Stageplay, + }; + } else if (fileIs(ExtensionHelper::markdown())) { + return { Domain::DocumentObjectType::Novel }; + } else if (fileIs(ExtensionHelper::plainText())) { + return { + Domain::DocumentObjectType::Audioplay, Domain::DocumentObjectType::ComicBook, + Domain::DocumentObjectType::Screenplay, Domain::DocumentObjectType::Stageplay, + Domain::DocumentObjectType::Novel, + }; + } + // + // Специализированные форматы + // + else if (fileIs(ExtensionHelper::celtx()) || fileIs(ExtensionHelper::finalDraft()) + || fileIs(ExtensionHelper::finalDraftTemplate()) + || fileIs(ExtensionHelper::kitScenarist()) || fileIs(ExtensionHelper::trelby())) { + return { Domain::DocumentObjectType::Screenplay }; + } + return { Domain::DocumentObjectType::Undefined }; +} + } // namespace class ImportDialog::Implementation { public: - Implementation(const QString& _importFilePath, QWidget* _parent); + Implementation(const QStringList& _importFilePaths, ImportDialog* _parent); /** - * @brief Задать типы документов, в которые можем импортировать + * @brief Текущие опции импорта + */ + BusinessLayer::ImportOptions* currentOptions() const; + + /** + * @brief Записать текущие настройки импорта в список опций */ - void setImportDocumentTypes(const QVector>& _types); + void writeCurrentOptions(); /** - * @brief Получить тип документа, в который будем экспортировать + * @brief Текущий тип документа, в который будет импортирован файл */ - Domain::DocumentObjectType importInType() const; + Domain::DocumentObjectType currentType() const; + + /** + * @brief Задать типы документов, в которые можем импортировать + */ + void setImportDocumentTypes(const QVector& _types); /** * @brief Обновить лейбл галочки импортирования текста в зависимости от текущего типа документа */ void updateImportTextLabel(); + /** + * @brief Обновить видимость параметров + */ + void updateParametersVisibility(); + + /** + * @brief Отобразить настройки импорта для файла + */ + void showOptionsForFile(const QString& _path); + + /** + * @brief Доступен ли импорт при текущих настройках + */ + bool isImportAvailable() const; + + /** + * @brief Может ли файл быть импортирован + */ + bool fileCanBeImported(const BusinessLayer::ImportOptions* _options) const; + + /** + * @brief Сохранить настройки импорта для файлов + */ + void saveSetting(); + + + ImportDialog* q = nullptr; - const QString importFilePath; + const QStringList importFilePaths; + OverlineLabel* filesCountTitle = nullptr; + Tree* tree = nullptr; + Widget* optionsWidget = nullptr; ComboBox* documentType = nullptr; OverlineLabel* documentsTitle = nullptr; CheckBox* importCharacters = nullptr; @@ -59,77 +197,138 @@ class ImportDialog::Implementation CheckBox* importText = nullptr; CheckBox* keepSceneNumbers = nullptr; - QHBoxLayout* buttonsLayout = nullptr; + QHBoxLayout* bottomLayout = nullptr; + CheckBox* sameOptions = nullptr; Button* cancelButton = nullptr; Button* importButton = nullptr; + QString currentFile; QVector documentTypes; -}; + /** + * @brief Список опций импорта всех файлов + */ + std::unordered_map> filesOptions; +}; -ImportDialog::Implementation::Implementation(const QString& _importFilePath, QWidget* _parent) - : importFilePath(_importFilePath) - , documentType(new ComboBox(_parent)) - , documentsTitle(new OverlineLabel(_parent)) - , importCharacters(new CheckBox(_parent)) - , importLocations(new CheckBox(_parent)) - , importResearch(new CheckBox(_parent)) - , textTitle(new OverlineLabel(_parent)) - , importText(new CheckBox(_parent)) - , keepSceneNumbers(new CheckBox(_parent)) - , buttonsLayout(new QHBoxLayout) +ImportDialog::Implementation::Implementation(const QStringList& _importFilePaths, + ImportDialog* _parent) + : q(_parent) + , importFilePaths(_importFilePaths) + , filesCountTitle(new OverlineLabel(_parent)) + , tree(new Tree(_parent)) + , optionsWidget(new Widget(_parent)) + , documentType(new ComboBox(optionsWidget)) + , documentsTitle(new OverlineLabel(optionsWidget)) + , importCharacters(new CheckBox(optionsWidget)) + , importLocations(new CheckBox(optionsWidget)) + , importResearch(new CheckBox(optionsWidget)) + , textTitle(new OverlineLabel(optionsWidget)) + , importText(new CheckBox(optionsWidget)) + , keepSceneNumbers(new CheckBox(optionsWidget)) + , bottomLayout(new QHBoxLayout) + , sameOptions(new CheckBox(_parent)) , cancelButton(new Button(_parent)) , importButton(new Button(_parent)) + , currentFile(_importFilePaths.first()) { documentType->setSpellCheckPolicy(SpellCheckPolicy::Manual); - for (auto checkBox : { - importCharacters, - importLocations, - importResearch, - importText, - keepSceneNumbers, - }) { - checkBox->setChecked(true); - } + sameOptions->setChecked(false); - keepSceneNumbers->setChecked(false); + bottomLayout->setContentsMargins({}); + bottomLayout->setSpacing(0); + if (_importFilePaths.size() > 1) { + bottomLayout->addWidget(sameOptions); + } + bottomLayout->addStretch(); + bottomLayout->addWidget(cancelButton); + bottomLayout->addWidget(importButton); - buttonsLayout->setContentsMargins({}); - buttonsLayout->setSpacing(0); - buttonsLayout->addStretch(); - buttonsLayout->addWidget(cancelButton); - buttonsLayout->addWidget(importButton); + // + // Заполняем опции импорта файлов + // + QSettings settings; + for (const auto& path : _importFilePaths) { + std::unique_ptr options; + + const auto defaultType = typeToString(Domain::DocumentObjectType::Screenplay); + const auto type = stringToType( + settings.value(settingsKey(path, kDocumentType), defaultType).toString()); + if (type == Domain::DocumentObjectType::Screenplay) { + options = std::make_unique(); + auto screenplayOptions + = static_cast(options.get()); + screenplayOptions->importResearch + = settings.value(settingsKey(path, kImportResearch), true).toBool(); + screenplayOptions->keepSceneNumbers + = settings.value(settingsKey(path, kKeepSceneNumbers), false).toBool(); + } else { + options = std::make_unique(); + } + options->documentType = type; + options->filePath = path; + options->importCharacters + = settings.value(settingsKey(path, kImportCharacters), true).toBool(); + options->importLocations + = settings.value(settingsKey(path, kImportLocations), true).toBool(); + options->importText = settings.value(settingsKey(path, kImportText), true).toBool(); + filesOptions[path] = std::move(options); + } } -void ImportDialog::Implementation::setImportDocumentTypes( - const QVector>& _types) +BusinessLayer::ImportOptions* ImportDialog::Implementation::currentOptions() const { - QStringList list; - for (const auto& type : _types) { - list.append(type.first); - documentTypes.append(type.second); - } - auto documentTypesModel = new QStringListModel(list); - documentType->setModel(documentTypesModel); - - QSettings settings; - if (const int index = list.indexOf(settings.value(kDocumentType, "").toString()); index >= 0) { - documentType->setCurrentIndex(documentType->model()->index(index, 0)); + BusinessLayer::ImportOptions* options = nullptr; + const auto type = currentType(); + if (type == Domain::DocumentObjectType::Screenplay) { + options = new BusinessLayer::ScreenplayImportOptions; + auto screenplayOptions = static_cast(options); + screenplayOptions->importResearch + = importResearch->isVisibleTo(optionsWidget) && importResearch->isChecked(); + screenplayOptions->keepSceneNumbers + = keepSceneNumbers->isVisibleTo(optionsWidget) && keepSceneNumbers->isChecked(); } else { - documentType->setCurrentIndex(documentType->model()->index(0, 0)); + options = new BusinessLayer::ImportOptions; } + options->filePath = currentFile; + options->documentType = type; + options->importText = importText->isVisibleTo(optionsWidget) && importText->isChecked(); + + options->importCharacters + = importCharacters->isVisibleTo(optionsWidget) && importCharacters->isChecked(); + options->importLocations + = importLocations->isVisibleTo(optionsWidget) && importLocations->isChecked(); + return options; +} + +void ImportDialog::Implementation::writeCurrentOptions() +{ + filesOptions[currentFile].reset(currentOptions()); } -Domain::DocumentObjectType ImportDialog::Implementation::importInType() const +Domain::DocumentObjectType ImportDialog::Implementation::currentType() const { return documentTypes.value(documentType->currentIndex().row(), Domain::DocumentObjectType::Undefined); } +void ImportDialog::Implementation::setImportDocumentTypes( + const QVector& _types) +{ + documentTypes.clear(); + QStringList list; + for (const auto& type : _types) { + list.append(typeToString(type)); + documentTypes.append(type); + } + QSignalBlocker signalBlocker(documentType); + documentType->setModel(new QStringListModel(list)); +} + void ImportDialog::Implementation::updateImportTextLabel() { - switch (importInType()) { + switch (currentType()) { case Domain::DocumentObjectType::Audioplay: case Domain::DocumentObjectType::ComicBook: case Domain::DocumentObjectType::Screenplay: @@ -148,139 +347,359 @@ void ImportDialog::Implementation::updateImportTextLabel() } } +void ImportDialog::Implementation::updateParametersVisibility() +{ + auto isImportCharactersVisible = true; + auto isImportLocationsVisible = true; + auto isImportResearchVisible = true; + auto isKeepSceneNumbersVisible = true; + switch (currentType()) { + case Domain::DocumentObjectType::Audioplay: + case Domain::DocumentObjectType::ComicBook: + case Domain::DocumentObjectType::Stageplay: { + isImportLocationsVisible = false; + isImportResearchVisible = false; + isKeepSceneNumbersVisible = false; + break; + } + case Domain::DocumentObjectType::Novel: { + isImportCharactersVisible = false; + isImportLocationsVisible = false; + isImportResearchVisible = false; + isKeepSceneNumbersVisible = false; + break; + } + case Domain::DocumentObjectType::Screenplay: { + isKeepSceneNumbersVisible = importText->isChecked(); + break; + } + default: { + isImportLocationsVisible = false; + isImportResearchVisible = false; + isKeepSceneNumbersVisible = false; + break; + } + } + importCharacters->setVisible(isImportCharactersVisible); + importLocations->setVisible(isImportLocationsVisible); + importResearch->setVisible(isImportResearchVisible); + keepSceneNumbers->setVisible(isKeepSceneNumbersVisible); + documentsTitle->setVisible(isImportCharactersVisible || isImportLocationsVisible); + + updateImportTextLabel(); +} + +void ImportDialog::Implementation::showOptionsForFile(const QString& _path) +{ + const auto& options = filesOptions[_path]; + const auto type = options->documentType; + int index = documentTypes.indexOf(type) >= 0 ? documentTypes.indexOf(type) : 0; + documentType->setCurrentIndex(documentType->model()->index(index, 0)); + updateParametersVisibility(); + + importText->setChecked(options->importText); + importCharacters->setChecked(options->importCharacters); + importLocations->setChecked(options->importLocations); + + if (type == Domain::DocumentObjectType::Screenplay) { + auto screenplayOptions + = static_cast(options.get()); + importResearch->setChecked(screenplayOptions->importResearch); + keepSceneNumbers->setChecked(screenplayOptions->keepSceneNumbers); + } +} + +bool ImportDialog::Implementation::isImportAvailable() const +{ + return (importCharacters->isVisibleTo(optionsWidget) && importCharacters->isChecked()) + || (importLocations->isVisibleTo(optionsWidget) && importLocations->isChecked()) + || (importResearch->isVisibleTo(optionsWidget) && importResearch->isChecked()) + || (importText->isVisibleTo(optionsWidget) && importText->isChecked()); +} + +bool ImportDialog::Implementation::fileCanBeImported( + const BusinessLayer::ImportOptions* _options) const +{ + if (_options->documentType == Domain::DocumentObjectType::Screenplay) { + auto screenplayOptions + = static_cast(_options); + if (screenplayOptions->importResearch) { + return true; + } + } + if (_options->importCharacters || _options->importLocations || _options->importText) { + return true; + } + return false; +} + +void ImportDialog::Implementation::saveSetting() +{ + QSettings settings; + for (const auto& fileOptions : filesOptions) { + const auto& options = fileOptions.second; + const auto type = options->documentType; + if (type == Domain::DocumentObjectType::Screenplay) { + auto screenplayOptions + = static_cast(options.get()); + settings.setValue(settingsKey(options->filePath, kImportResearch), + screenplayOptions->importResearch); + settings.setValue(settingsKey(options->filePath, kKeepSceneNumbers), + screenplayOptions->keepSceneNumbers); + } + settings.setValue(settingsKey(options->filePath, kDocumentType), typeToString(type)); + settings.setValue(settingsKey(options->filePath, kImportCharacters), + options->importCharacters); + settings.setValue(settingsKey(options->filePath, kImportLocations), + options->importLocations); + settings.setValue(settingsKey(options->filePath, kImportText), options->importText); + } +} + // **** -ImportDialog::ImportDialog(const QString& _importFilePath, QWidget* _parent) +ImportDialog::ImportDialog(const QStringList& _importFilePaths, QWidget* _parent) : AbstractDialog(_parent) - , d(new Implementation(_importFilePath, this)) + , d(new Implementation(_importFilePaths, this)) { setAcceptButton(d->importButton); setRejectButton(d->cancelButton); - int row = 0; - contentsLayout()->addWidget(d->documentType, row++, 0); - contentsLayout()->addWidget(d->documentsTitle, row++, 0); - contentsLayout()->addWidget(d->importCharacters, row++, 0); - contentsLayout()->addWidget(d->importLocations, row++, 0); - contentsLayout()->addWidget(d->importResearch, row++, 0); - contentsLayout()->addWidget(d->textTitle, row++, 0); - contentsLayout()->addWidget(d->importText, row++, 0); - contentsLayout()->addWidget(d->keepSceneNumbers, row++, 0); - contentsLayout()->addLayout(d->buttonsLayout, row++, 0); + int column = 0; + if (_importFilePaths.size() > 1) { + QStandardItemModel* model = new QStandardItemModel(d->tree); + for (const auto& path : _importFilePaths) { + const auto& options = d->filesOptions[path]; + const auto type = options->documentType; + auto item = new QStandardItem(path); + item->setData(typeToString(type), ImportTypeRole); + item->setData(d->fileCanBeImported(options.get()), ImportEnabledRole); + model->appendRow(item); + } + d->tree->setModel(model); + d->tree->setItemDelegate(new FileNameDelegate(d->tree)); + d->tree->setCurrentIndex(d->tree->model()->index(0, 0)); + + // + // Левая сторона + // + QVBoxLayout* leftLayout = new QVBoxLayout; + leftLayout->addWidget(d->filesCountTitle); + leftLayout->addWidget(d->tree); + contentsLayout()->addLayout(leftLayout, 0, column++); + } + + // + // Правая сторона + // + QVBoxLayout* rightLayout = new QVBoxLayout; + rightLayout->addWidget(d->documentType); + rightLayout->addWidget(d->documentsTitle); + rightLayout->addWidget(d->importCharacters); + rightLayout->addWidget(d->importLocations); + rightLayout->addWidget(d->importResearch); + rightLayout->addWidget(d->textTitle); + rightLayout->addWidget(d->importText); + rightLayout->addWidget(d->keepSceneNumbers); + rightLayout->addStretch(); + d->optionsWidget->setLayout(rightLayout); + contentsLayout()->addWidget(d->optionsWidget, 0, column); + // + // Низ + // + int columnSpan = column + 1; + contentsLayout()->addLayout(d->bottomLayout, 1, 0, 1, columnSpan); + + // + // Определить активность кнопки импорта + // auto configureImportAvailability = [this] { - d->importButton->setEnabled( - (d->importCharacters->isVisibleTo(this) && d->importCharacters->isChecked()) - || (d->importLocations->isVisibleTo(this) && d->importLocations->isChecked()) - || (d->importResearch->isVisibleTo(this) && d->importResearch->isChecked()) - || (d->importText->isVisibleTo(this) && d->importText->isChecked())); + bool importEnabled = true; + const auto currentFileImportAvailable = d->isImportAvailable(); + if (d->tree->model()) { + d->tree->model()->setData(d->tree->currentIndex(), currentFileImportAvailable, + ImportEnabledRole); + } + if (d->sameOptions->isVisibleTo(this) && d->sameOptions->isChecked()) { + importEnabled = currentFileImportAvailable; + } else if (!currentFileImportAvailable) { + importEnabled = false; + } else { + for (const auto& fileOptions : d->filesOptions) { + const auto& options = fileOptions.second; + if (!d->fileCanBeImported(options.get()) && options->filePath != d->currentFile) { + importEnabled = false; + break; + } + } + } + d->importButton->setEnabled(importEnabled); }; + configureImportAvailability(); + + // + // Соединения чекбоксов настроек импорта + // connect(d->importCharacters, &CheckBox::checkedChanged, this, configureImportAvailability); connect(d->importLocations, &CheckBox::checkedChanged, this, configureImportAvailability); connect(d->importResearch, &CheckBox::checkedChanged, this, configureImportAvailability); connect(d->importText, &CheckBox::checkedChanged, this, configureImportAvailability); connect(d->importText, &CheckBox::checkedChanged, this, [this](bool _checked) { - if (d->importInType() == Domain::DocumentObjectType::Screenplay) { + if (d->currentType() == Domain::DocumentObjectType::Screenplay) { d->keepSceneNumbers->setVisible(_checked); } }); - connect(d->importButton, &Button::clicked, this, &ImportDialog::importRequested); - connect(d->cancelButton, &Button::clicked, this, &ImportDialog::canceled); - auto updateParameters = [this] { - auto isImportCharactersVisible = true; - auto isImportLocationsVisible = true; - auto isImportResearchVisible = true; - auto isKeepSceneNumbersVisible = true; - switch (d->importInType()) { - case Domain::DocumentObjectType::Audioplay: - case Domain::DocumentObjectType::ComicBook: - case Domain::DocumentObjectType::Stageplay: { - isImportLocationsVisible = false; - isImportResearchVisible = false; - isKeepSceneNumbersVisible = false; - break; - } - case Domain::DocumentObjectType::Novel: { - isImportCharactersVisible = false; - isImportLocationsVisible = false; - isImportResearchVisible = false; - isKeepSceneNumbersVisible = false; - break; - } - case Domain::DocumentObjectType::Screenplay: { - // - // ... всё видимое - // - break; - } - default: { - isImportLocationsVisible = false; - isImportResearchVisible = false; - isKeepSceneNumbersVisible = false; - break; - } + // + // Передать опции импорта всем файлам + // + auto setSameOptionsForAll = [this] { + if (d->sameOptions->isVisibleTo(this) && d->sameOptions->isChecked()) { + QScopedPointer currentOptions(d->currentOptions()); + + for (auto& fileOptions : d->filesOptions) { + auto& options = fileOptions.second; + if (options->documentType != currentOptions->documentType) { + const auto path = options->filePath; + options.reset(d->currentOptions()); + options->filePath = path; + } + if (options->documentType == Domain::DocumentObjectType::Screenplay) { + auto currentScreenplayOptions + = static_cast( + currentOptions.get()); + auto screenplayOptions + = static_cast(options.get()); + screenplayOptions->importResearch = currentScreenplayOptions->importResearch; + screenplayOptions->keepSceneNumbers + = currentScreenplayOptions->keepSceneNumbers; + } + options->importCharacters = currentOptions->importCharacters; + options->importLocations = currentOptions->importLocations; + options->importText = currentOptions->importText; + + auto model = static_cast(d->tree->model()); + auto items = model->findItems(options->filePath); + if (!items.isEmpty()) { + items.first()->setData(typeToString(options->documentType), ImportTypeRole); + items.first()->setData(d->fileCanBeImported(options.get()), ImportEnabledRole); + } + } + d->tree->update(); } - d->importCharacters->setVisible(isImportCharactersVisible); - d->importLocations->setVisible(isImportLocationsVisible); - d->importResearch->setVisible(isImportResearchVisible); - d->keepSceneNumbers->setVisible(isKeepSceneNumbersVisible); - d->documentsTitle->setVisible(isImportCharactersVisible || isImportLocationsVisible); + }; - d->updateImportTextLabel(); + // + // Соединения для работы чекбокса "Same options for all" + // + connect(d->sameOptions, &CheckBox::checkedChanged, this, + [this, setSameOptionsForAll](bool _checked) { + if (_checked) { + d->importButton->setEnabled(d->isImportAvailable()); + setSameOptionsForAll(); + } + }); + connect(d->importCharacters, &CheckBox::checkedChanged, this, setSameOptionsForAll); + connect(d->importLocations, &CheckBox::checkedChanged, this, setSameOptionsForAll); + connect(d->importText, &CheckBox::checkedChanged, this, setSameOptionsForAll); + connect(d->importResearch, &CheckBox::checkedChanged, this, setSameOptionsForAll); + connect(d->keepSceneNumbers, &CheckBox::checkedChanged, this, setSameOptionsForAll); + + // + // Определить активность чекбокса "Same options for all" + // + auto setSameOptionsAvailable = [this] { + bool state = d->sameOptions->isChecked(); + bool isEnabled = true; + for (const auto& fileOptions : d->filesOptions) { + if (!importTypesForFile(fileOptions.second->filePath).contains(d->currentType())) { + state = false; + isEnabled = false; + break; + } + } + d->sameOptions->setChecked(state); + d->sameOptions->setEnabled(isEnabled); + return isEnabled; }; - connect(d->documentType, &ComboBox::currentIndexChanged, this, updateParameters); + // + // Соединение комбобокса типов для импорта + // + connect(d->documentType, &ComboBox::currentIndexChanged, this, + [this, setSameOptionsAvailable, configureImportAvailability, setSameOptionsForAll] { + d->updateParametersVisibility(); + if (d->tree->model()) { + const auto a = d->documentType->currentText(); + d->tree->model()->setData(d->tree->currentIndex(), + d->documentType->currentText(), ImportTypeRole); + const bool sameOptionsAvailable = setSameOptionsAvailable(); + configureImportAvailability(); + if (sameOptionsAvailable) { + setSameOptionsForAll(); + } + } + }); - QSettings settings; - d->importCharacters->setChecked(settings.value(kImportCharacters, true).toBool()); - d->importLocations->setChecked(settings.value(kImportLocations, true).toBool()); - d->importResearch->setChecked(settings.value(kImportResearch, true).toBool()); - d->importText->setChecked(settings.value(kImportText, true).toBool()); - d->keepSceneNumbers->setChecked(settings.value(kKeepSceneNumbers, false).toBool()); + // + // Соединение списка файлов + // + connect(d->tree, &Tree::currentIndexChanged, this, + [this, setSameOptionsAvailable](const QModelIndex& _index) { + d->writeCurrentOptions(); + const bool sameOptionsState = d->sameOptions->isChecked(); + d->currentFile = _index.data().toString(); + d->setImportDocumentTypes(importTypesForFile(d->currentFile)); + d->showOptionsForFile(d->currentFile); + const bool sameOptionsAvailable = setSameOptionsAvailable(); + if (sameOptionsAvailable) { + d->sameOptions->setChecked(sameOptionsState); + } + }); + + // + // Соединения кнопок импорта/отмены + // + connect(d->importButton, &Button::clicked, this, &ImportDialog::importRequested); + connect(d->cancelButton, &Button::clicked, this, &ImportDialog::canceled); + + // + // Если импортируем один файл, прячем лишние виджеты + // + if (_importFilePaths.size() == 1) { + d->tree->setVisible(false); + d->sameOptions->setVisible(false); + d->filesCountTitle->setVisible(false); + } + + // + // Отображаем настройки текущего файла + // + d->setImportDocumentTypes(importTypesForFile(d->currentFile)); + d->showOptionsForFile(d->currentFile); + d->sameOptions->setChecked(false); + setSameOptionsAvailable(); } ImportDialog::~ImportDialog() { - QSettings settings; - settings.setValue(kDocumentType, d->documentType->currentText()); - settings.setValue(kImportCharacters, d->importCharacters->isChecked()); - settings.setValue(kImportLocations, d->importLocations->isChecked()); - settings.setValue(kImportResearch, d->importResearch->isChecked()); - settings.setValue(kImportText, d->importText->isChecked()); - settings.setValue(kKeepSceneNumbers, d->keepSceneNumbers->isChecked()); + d->writeCurrentOptions(); + d->saveSetting(); } -BusinessLayer::ImportOptions ImportDialog::importOptions() const +std::vector> ImportDialog::importOptions() const { - BusinessLayer::ImportOptions options; - options.filePath = d->importFilePath; - options.documentType = d->importInType(); - options.importText = d->importText->isVisibleTo(this) && d->importText->isChecked(); - - options.importCharacters - = d->importCharacters->isVisibleTo(this) && d->importCharacters->isChecked(); - options.importLocations - = d->importLocations->isVisibleTo(this) && d->importLocations->isChecked(); - return options; -} + d->writeCurrentOptions(); + d->saveSetting(); -BusinessLayer::ScreenplayImportOptions ImportDialog::screenplayImportOptions() const -{ - BusinessLayer::ScreenplayImportOptions options; - options.filePath = d->importFilePath; - options.documentType = d->importInType(); - options.importText = d->importText->isVisibleTo(this) && d->importText->isChecked(); - - options.importCharacters - = d->importCharacters->isVisibleTo(this) && d->importCharacters->isChecked(); - options.importLocations - = d->importLocations->isVisibleTo(this) && d->importLocations->isChecked(); - options.importResearch = d->importResearch->isVisibleTo(this) && d->importResearch->isChecked(); - options.keepSceneNumbers - = d->keepSceneNumbers->isVisibleTo(this) && d->keepSceneNumbers->isChecked(); + std::vector> options; + for (auto& fileOptions : d->filesOptions) { + options.push_back(std::move(fileOptions.second)); + } + d->filesOptions.clear(); return options; } @@ -296,9 +715,14 @@ QWidget* ImportDialog::lastFocusableWidget() const void ImportDialog::updateTranslations() { - const QFileInfo importFileInfo(d->importFilePath); - setTitle(QString("%1 \"%2\"").arg(tr("Import data from the file"), importFileInfo.fileName())); + if (d->filesOptions.size() > 1) { + setTitle(tr("Import data from files")); + } else { + QFileInfo fileInfo(d->currentFile); + setTitle(QString("%1 \"%2\"").arg(tr("Import data from the file"), fileInfo.fileName())); + } + d->filesCountTitle->setText(QString(tr("Importing files (%n)", 0, d->importFilePaths.count()))); d->documentsTitle->setText(tr("Documents")); d->importCharacters->setText(tr("Import characters")); d->importLocations->setText(tr("Import locations")); @@ -307,47 +731,39 @@ void ImportDialog::updateTranslations() d->updateImportTextLabel(); d->keepSceneNumbers->setText(tr("Keep scene numbers")); + d->sameOptions->setText(tr("Same options for all")); d->importButton->setText(tr("Import")); d->cancelButton->setText(tr("Cancel")); - auto fileIs = [filePath = d->importFilePath.toLower()](const QString& _extension) { - return filePath.endsWith(_extension); - }; - - const auto audioplay = qMakePair(tr("Audioplay"), Domain::DocumentObjectType::Audioplay); - const auto comicBook = qMakePair(tr("Comic Book"), Domain::DocumentObjectType::ComicBook); - const auto novel = qMakePair(tr("Novel"), Domain::DocumentObjectType::Novel); - const auto screenplay = qMakePair(tr("Screenplay"), Domain::DocumentObjectType::Screenplay); - const auto stageplay = qMakePair(tr("Stageplay"), Domain::DocumentObjectType::Stageplay); - - // - // Бинарные форматы - // - if (fileIs(ExtensionHelper::msOfficeOpenXml()) || fileIs(ExtensionHelper::openDocumentXml())) { - d->setImportDocumentTypes({ screenplay }); - } else if (fileIs(ExtensionHelper::pdf())) { - d->setImportDocumentTypes({ screenplay }); - } // - // Текстовые форматы + // Обновляем выпадающий список // - else if (fileIs(ExtensionHelper::fountain())) { - d->setImportDocumentTypes({ audioplay, comicBook, screenplay, stageplay }); - } else if (fileIs(ExtensionHelper::markdown())) { - d->setImportDocumentTypes({ novel }); - } else if (fileIs(ExtensionHelper::plainText())) { - d->setImportDocumentTypes({ audioplay, comicBook, screenplay, stageplay, novel }); - } + d->setImportDocumentTypes(importTypesForFile(d->currentFile)); + d->showOptionsForFile(d->currentFile); + + d->documentType->setLabel(tr("Import to")); + // - // Специализированные форматы + // После установки текста фиксируем размер виджета опций // - else if (fileIs(ExtensionHelper::celtx()) || fileIs(ExtensionHelper::finalDraft()) - || fileIs(ExtensionHelper::finalDraftTemplate()) - || fileIs(ExtensionHelper::kitScenarist()) || fileIs(ExtensionHelper::trelby())) { - d->setImportDocumentTypes({ screenplay }); + if (d->filesOptions.size() > 1) { + QList> optionsVisability; + for (auto* option : { + d->importCharacters, + d->importLocations, + d->importResearch, + d->importText, + d->keepSceneNumbers, + }) { + optionsVisability.append(QPair(option, option->isVisibleTo(d->optionsWidget))); + option->setVisible(true); + } + d->optionsWidget->adjustSize(); + d->optionsWidget->setFixedSize(d->optionsWidget->size()); + for (auto option : optionsVisability) { + option.first->setVisible(option.second); + } } - - d->documentType->setLabel(tr("Import to")); } void ImportDialog::designSystemChangeEvent(DesignSystemChangeEvent* _event) @@ -357,6 +773,16 @@ void ImportDialog::designSystemChangeEvent(DesignSystemChangeEvent* _event) auto titleMargins = Ui::DesignSystem::label().margins().toMargins(); titleMargins.setTop(Ui::DesignSystem::layout().px8()); titleMargins.setBottom(0); + + d->tree->setBackgroundColor(DesignSystem::color().primary()); + d->tree->setTextColor(DesignSystem::color().onPrimary()); + + d->filesCountTitle->setContentsMargins(titleMargins); + d->filesCountTitle->setBackgroundColor(Ui::DesignSystem::color().background()); + d->filesCountTitle->setTextColor(Ui::DesignSystem::color().onBackground()); + + d->optionsWidget->setBackgroundColor(DesignSystem::color().background()); + for (auto label : { d->documentsTitle, d->textTitle }) { label->setContentsMargins(titleMargins); label->setBackgroundColor(Ui::DesignSystem::color().background()); @@ -369,6 +795,7 @@ void ImportDialog::designSystemChangeEvent(DesignSystemChangeEvent* _event) d->importResearch, d->importText, d->keepSceneNumbers, + d->sameOptions, }) { checkBox->setBackgroundColor(Ui::DesignSystem::color().background()); checkBox->setTextColor(Ui::DesignSystem::color().onBackground()); @@ -396,7 +823,7 @@ void ImportDialog::designSystemChangeEvent(DesignSystemChangeEvent* _event) } contentsLayout()->setSpacing(static_cast(Ui::DesignSystem::layout().px8())); - d->buttonsLayout->setContentsMargins( + d->bottomLayout->setContentsMargins( QMarginsF(Ui::DesignSystem::layout().px12(), Ui::DesignSystem::layout().px12(), Ui::DesignSystem::layout().px16(), Ui::DesignSystem::layout().px16()) .toMargins()); diff --git a/src/core/ui/import/import_dialog.h b/src/core/ui/import/import_dialog.h index e403f8271..df9e74273 100644 --- a/src/core/ui/import/import_dialog.h +++ b/src/core/ui/import/import_dialog.h @@ -18,14 +18,19 @@ class ImportDialog : public AbstractDialog Q_OBJECT public: - explicit ImportDialog(const QString& _importFilePath, QWidget* _parent = nullptr); + enum DataRole { + ImportTypeRole = Qt::UserRole + 1, + ImportEnabledRole, + }; + +public: + explicit ImportDialog(const QStringList& _importFilePaths, QWidget* _parent = nullptr); ~ImportDialog() override; /** * @brief Получить заданные опции импортирования */ - BusinessLayer::ImportOptions importOptions() const; - BusinessLayer::ScreenplayImportOptions screenplayImportOptions() const; + std::vector> importOptions() const; signals: /** diff --git a/src/core/ui/menu_view.cpp b/src/core/ui/menu_view.cpp index 69b9035c3..05cb8681f 100644 --- a/src/core/ui/menu_view.cpp +++ b/src/core/ui/menu_view.cpp @@ -547,7 +547,7 @@ void MenuView::updateTranslations() d->saveProject->setWhatsThis( QKeySequence(QKeySequence::Save).toString(QKeySequence::NativeText)); d->saveProjectAs->setText(tr("Save story as...")); - d->importProject->setText(tr("Import document...")); + d->importProject->setText(tr("Import documents...")); d->exportCurrentDocument->setText(tr("Export current document...")); d->fullScreen->setText(tr("Full screen")); d->fullScreen->setWhatsThis( diff --git a/src/corelib/business_layer/import/abstract_document_importer.cpp b/src/corelib/business_layer/import/abstract_document_importer.cpp index 66882c59b..04230faf0 100644 --- a/src/corelib/business_layer/import/abstract_document_importer.cpp +++ b/src/corelib/business_layer/import/abstract_document_importer.cpp @@ -161,13 +161,13 @@ AbstractDocumentImporter::~AbstractDocumentImporter() = default; AbstractImporter::Documents AbstractDocumentImporter::importDocuments( - const ImportOptions& _options) const + const ImportOptions* _options) const { // // Преобразовать заданный документ в QTextDocument // QTextDocument document; - const bool documentDone = documentForImport(_options.filePath, document); + const bool documentDone = documentForImport(_options->filePath, document); if (!documentDone) { return {}; } @@ -240,7 +240,7 @@ AbstractImporter::Documents AbstractDocumentImporter::importDocuments( switch (blockType) { case TextParagraphType::SceneHeading: { - if (!_options.importLocations) { + if (!_options->importLocations) { break; } @@ -254,7 +254,7 @@ AbstractImporter::Documents AbstractDocumentImporter::importDocuments( } case TextParagraphType::Character: { - if (!_options.importCharacters) { + if (!_options->importCharacters) { break; } @@ -298,7 +298,7 @@ AbstractImporter::Documents AbstractDocumentImporter::importDocuments( return documents; } -QString AbstractDocumentImporter::parseDocument(const ImportOptions& _options, +QString AbstractDocumentImporter::parseDocument(const ImportOptions* _options, QTextDocument& _document) const { // @@ -672,7 +672,7 @@ QRegularExpression AbstractDocumentImporter::startFromNumberChecker() const return kStartFromNumberChecker; } -bool AbstractDocumentImporter::shouldKeepSceneNumbers(const ImportOptions& _options) const +bool AbstractDocumentImporter::shouldKeepSceneNumbers(const ImportOptions* _options) const { Q_UNUSED(_options) diff --git a/src/corelib/business_layer/import/abstract_document_importer.h b/src/corelib/business_layer/import/abstract_document_importer.h index c7d62dc64..48d352d57 100644 --- a/src/corelib/business_layer/import/abstract_document_importer.h +++ b/src/corelib/business_layer/import/abstract_document_importer.h @@ -26,12 +26,12 @@ class CORE_LIBRARY_EXPORT AbstractDocumentImporter : virtual public AbstractImpo /** * @brief Импорт докуметов (всех, кроме сценариев) */ - Documents importDocuments(const ImportOptions& _options) const override; + Documents importDocuments(const ImportOptions* _options) const override; /** * @brief Получить из QTextDocument xml-строку */ - QString parseDocument(const ImportOptions& _options, QTextDocument& _document) const; + QString parseDocument(const ImportOptions* _options, QTextDocument& _document) const; protected: /** @@ -61,7 +61,7 @@ class CORE_LIBRARY_EXPORT AbstractDocumentImporter : virtual public AbstractImpo /** * @brief Следует ли сохранять номера сцен */ - virtual bool shouldKeepSceneNumbers(const ImportOptions& _options) const; + virtual bool shouldKeepSceneNumbers(const ImportOptions* _options) const; /** * @brief Записать редакторские заметки diff --git a/src/corelib/business_layer/import/abstract_fountain_importer.cpp b/src/corelib/business_layer/import/abstract_fountain_importer.cpp index f4f5665ee..4d29b1bdd 100644 --- a/src/corelib/business_layer/import/abstract_fountain_importer.cpp +++ b/src/corelib/business_layer/import/abstract_fountain_importer.cpp @@ -511,12 +511,12 @@ AbstractFountainImporter::AbstractFountainImporter( AbstractFountainImporter::~AbstractFountainImporter() = default; AbstractScreenplayImporter::Documents AbstractFountainImporter::importDocuments( - const ImportOptions& _options) const + const ImportOptions* _options) const { // // Открываем файл // - QFile fountainFile(_options.filePath); + QFile fountainFile(_options->filePath); if (!fountainFile.open(QIODevice::ReadOnly)) { return {}; } @@ -674,7 +674,7 @@ AbstractScreenplayImporter::Documents AbstractFountainImporter::importDocuments( switch (blockType) { case TextParagraphType::SceneHeading: { - if (!_options.importLocations) { + if (!_options->importLocations) { break; } @@ -686,7 +686,7 @@ AbstractScreenplayImporter::Documents AbstractFountainImporter::importDocuments( } case TextParagraphType::Character: { - if (!_options.importCharacters) { + if (!_options->importCharacters) { break; } diff --git a/src/corelib/business_layer/import/abstract_fountain_importer.h b/src/corelib/business_layer/import/abstract_fountain_importer.h index 4a8b7a5a2..688f0e18d 100644 --- a/src/corelib/business_layer/import/abstract_fountain_importer.h +++ b/src/corelib/business_layer/import/abstract_fountain_importer.h @@ -23,7 +23,7 @@ class CORE_LIBRARY_EXPORT AbstractFountainImporter : virtual public AbstractImpo /** * @brief Импорт докуметов (всех, кроме сценариев) */ - Documents importDocuments(const ImportOptions& _options) const override; + Documents importDocuments(const ImportOptions* _options) const override; protected: /** diff --git a/src/corelib/business_layer/import/abstract_importer.h b/src/corelib/business_layer/import/abstract_importer.h index a09c0c097..9ac7843e1 100644 --- a/src/corelib/business_layer/import/abstract_importer.h +++ b/src/corelib/business_layer/import/abstract_importer.h @@ -40,7 +40,7 @@ class CORE_LIBRARY_EXPORT AbstractImporter /** * @brief Импорт докуметов (всех, кроме сценариев) */ - virtual Documents importDocuments(const ImportOptions& _options) const = 0; + virtual Documents importDocuments(const ImportOptions* _options) const = 0; }; } // namespace BusinessLayer diff --git a/src/corelib/business_layer/import/audioplay/abstract_audioplay_importer.h b/src/corelib/business_layer/import/audioplay/abstract_audioplay_importer.h index 8bca6c0f9..a609fdcfd 100644 --- a/src/corelib/business_layer/import/audioplay/abstract_audioplay_importer.h +++ b/src/corelib/business_layer/import/audioplay/abstract_audioplay_importer.h @@ -28,7 +28,7 @@ class CORE_LIBRARY_EXPORT AbstractAudioplayImporter : virtual public AbstractImp /** * @brief Импорт аудиопьесы из заданного документа */ - virtual Audioplay importAudioplay(const ImportOptions& _options) const = 0; + virtual Audioplay importAudioplay(const ImportOptions* _options) const = 0; }; } // namespace BusinessLayer diff --git a/src/corelib/business_layer/import/audioplay/audioplay_fountain_importer.cpp b/src/corelib/business_layer/import/audioplay/audioplay_fountain_importer.cpp index 70e8ba842..5943915f3 100644 --- a/src/corelib/business_layer/import/audioplay/audioplay_fountain_importer.cpp +++ b/src/corelib/business_layer/import/audioplay/audioplay_fountain_importer.cpp @@ -42,16 +42,16 @@ AudioplayFountainImporter::AudioplayFountainImporter() AudioplayFountainImporter::~AudioplayFountainImporter() = default; AbstractAudioplayImporter::Audioplay AudioplayFountainImporter::importAudioplay( - const ImportOptions& _options) const + const ImportOptions* _options) const { - if (_options.importText == false) { + if (_options->importText == false) { return {}; } // // Открываем файл // - QFile fountainFile(_options.filePath); + QFile fountainFile(_options->filePath); if (!fountainFile.open(QIODevice::ReadOnly)) { return {}; } @@ -61,7 +61,7 @@ AbstractAudioplayImporter::Audioplay AudioplayFountainImporter::importAudioplay( // auto audioplay = audioplayText(fountainFile.readAll()); if (audioplay.name.isEmpty()) { - audioplay.name = QFileInfo(_options.filePath).completeBaseName(); + audioplay.name = QFileInfo(_options->filePath).completeBaseName(); } return audioplay; diff --git a/src/corelib/business_layer/import/audioplay/audioplay_fountain_importer.h b/src/corelib/business_layer/import/audioplay/audioplay_fountain_importer.h index 66ba51a74..6965077b1 100644 --- a/src/corelib/business_layer/import/audioplay/audioplay_fountain_importer.h +++ b/src/corelib/business_layer/import/audioplay/audioplay_fountain_importer.h @@ -41,7 +41,7 @@ class CORE_LIBRARY_EXPORT AudioplayFountainImporter : public AbstractAudioplayIm /** * @brief Импортировать аудиопьесу */ - Audioplay importAudioplay(const ImportOptions& _options) const override; + Audioplay importAudioplay(const ImportOptions* _options) const override; /** * @brief Получить основной текст аудиопьесы в формате xml из заданного текста diff --git a/src/corelib/business_layer/import/comic_book/abstract_comic_book_importer.h b/src/corelib/business_layer/import/comic_book/abstract_comic_book_importer.h index 8c14217a5..fd709d35e 100644 --- a/src/corelib/business_layer/import/comic_book/abstract_comic_book_importer.h +++ b/src/corelib/business_layer/import/comic_book/abstract_comic_book_importer.h @@ -30,7 +30,7 @@ class CORE_LIBRARY_EXPORT AbstractComicBookImporter : virtual public AbstractImp /** * @brief Импорт сценариев из заданного документа */ - virtual ComicBook importComicBook(const ImportOptions& _options) const = 0; + virtual ComicBook importComicBook(const ImportOptions* _options) const = 0; }; } // namespace BusinessLayer diff --git a/src/corelib/business_layer/import/comic_book/comic_book_fountain_importer.cpp b/src/corelib/business_layer/import/comic_book/comic_book_fountain_importer.cpp index e3750e906..1b306206e 100644 --- a/src/corelib/business_layer/import/comic_book/comic_book_fountain_importer.cpp +++ b/src/corelib/business_layer/import/comic_book/comic_book_fountain_importer.cpp @@ -60,16 +60,16 @@ ComicBookFountainImporter::ComicBookFountainImporter() ComicBookFountainImporter::~ComicBookFountainImporter() = default; AbstractComicBookImporter::ComicBook ComicBookFountainImporter::importComicBook( - const ImportOptions& _options) const + const ImportOptions* _options) const { - if (_options.importText == false) { + if (_options->importText == false) { return {}; } // // Открываем файл // - QFile fountainFile(_options.filePath); + QFile fountainFile(_options->filePath); if (!fountainFile.open(QIODevice::ReadOnly)) { return {}; } @@ -79,7 +79,7 @@ AbstractComicBookImporter::ComicBook ComicBookFountainImporter::importComicBook( // auto comicbook = comicbookText(fountainFile.readAll()); if (comicbook.name.isEmpty()) { - comicbook.name = QFileInfo(_options.filePath).completeBaseName(); + comicbook.name = QFileInfo(_options->filePath).completeBaseName(); } return comicbook; diff --git a/src/corelib/business_layer/import/comic_book/comic_book_fountain_importer.h b/src/corelib/business_layer/import/comic_book/comic_book_fountain_importer.h index 212447708..a5af065e1 100644 --- a/src/corelib/business_layer/import/comic_book/comic_book_fountain_importer.h +++ b/src/corelib/business_layer/import/comic_book/comic_book_fountain_importer.h @@ -22,7 +22,7 @@ class CORE_LIBRARY_EXPORT ComicBookFountainImporter : public AbstractComicBookIm /** * @brief Импортировать комикс */ - ComicBook importComicBook(const ImportOptions& _options) const override; + ComicBook importComicBook(const ImportOptions* _options) const override; /** * @brief Получить основной текст комикса в формате xml из заданного текста diff --git a/src/corelib/business_layer/import/novel/abstract_novel_importer.h b/src/corelib/business_layer/import/novel/abstract_novel_importer.h index 29f630d6f..0638fbbb3 100644 --- a/src/corelib/business_layer/import/novel/abstract_novel_importer.h +++ b/src/corelib/business_layer/import/novel/abstract_novel_importer.h @@ -28,7 +28,7 @@ class CORE_LIBRARY_EXPORT AbstractNovelImporter /** * @brief Импорт сценариев из заданного документа */ - virtual Document importNovel(const ImportOptions& _options) const = 0; + virtual Document importNovel(const ImportOptions* _options) const = 0; }; } // namespace BusinessLayer diff --git a/src/corelib/business_layer/import/novel/novel_markdown_importer.cpp b/src/corelib/business_layer/import/novel/novel_markdown_importer.cpp index 859e60978..98efcd28b 100644 --- a/src/corelib/business_layer/import/novel/novel_markdown_importer.cpp +++ b/src/corelib/business_layer/import/novel/novel_markdown_importer.cpp @@ -68,12 +68,12 @@ NovelMarkdownImporter::NovelMarkdownImporter() NovelMarkdownImporter::~NovelMarkdownImporter() = default; AbstractNovelImporter::Document NovelMarkdownImporter::importNovel( - const ImportOptions& _options) const + const ImportOptions* _options) const { // // Открываем файл // - QFile textFile(_options.filePath); + QFile textFile(_options->filePath); if (!textFile.open(QIODevice::ReadOnly)) { return {}; } @@ -83,7 +83,7 @@ AbstractNovelImporter::Document NovelMarkdownImporter::importNovel( // Document textDocument = novelText(textFile.readAll()); if (textDocument.name.isEmpty()) { - textDocument.name = QFileInfo(_options.filePath).completeBaseName(); + textDocument.name = QFileInfo(_options->filePath).completeBaseName(); } return textDocument; diff --git a/src/corelib/business_layer/import/novel/novel_markdown_importer.h b/src/corelib/business_layer/import/novel/novel_markdown_importer.h index 24534adaf..83940c54b 100644 --- a/src/corelib/business_layer/import/novel/novel_markdown_importer.h +++ b/src/corelib/business_layer/import/novel/novel_markdown_importer.h @@ -20,7 +20,7 @@ class CORE_LIBRARY_EXPORT NovelMarkdownImporter : public AbstractNovelImporter, /** * @brief Импортировать роман */ - Document importNovel(const ImportOptions& _options) const override; + Document importNovel(const ImportOptions* _options) const override; /** * @brief Получить основной текст романа в формате xml из заданного текста diff --git a/src/corelib/business_layer/import/screenplay/abstract_screenplay_importer.h b/src/corelib/business_layer/import/screenplay/abstract_screenplay_importer.h index 6ba002a07..d5f01dc30 100644 --- a/src/corelib/business_layer/import/screenplay/abstract_screenplay_importer.h +++ b/src/corelib/business_layer/import/screenplay/abstract_screenplay_importer.h @@ -35,7 +35,7 @@ class CORE_LIBRARY_EXPORT AbstractScreenplayImporter : virtual public AbstractIm * @brief Импорт сценариев из заданного документа */ virtual QVector importScreenplays( - const ScreenplayImportOptions& _options) const = 0; + const ScreenplayImportOptions* _options) const = 0; }; } // namespace BusinessLayer diff --git a/src/corelib/business_layer/import/screenplay/screenplay_celtx_importer.cpp b/src/corelib/business_layer/import/screenplay/screenplay_celtx_importer.cpp index d7cd98428..3408800dc 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_celtx_importer.cpp +++ b/src/corelib/business_layer/import/screenplay/screenplay_celtx_importer.cpp @@ -55,12 +55,12 @@ QString readScript(const QString& _filePath) } // namespace AbstractScreenplayImporter::Documents ScreenplayCeltxImporter::importDocuments( - const ImportOptions& _options) const + const ImportOptions* _options) const { // // Открываем файл // - const auto scriptHtml = readScript(_options.filePath); + const auto scriptHtml = readScript(_options->filePath); if (scriptHtml.isEmpty()) { return {}; } @@ -89,7 +89,7 @@ AbstractScreenplayImporter::Documents ScreenplayCeltxImporter::importDocuments( switch (blockType) { case TextParagraphType::SceneHeading: { - if (!_options.importLocations) { + if (!_options->importLocations) { break; } @@ -103,7 +103,7 @@ AbstractScreenplayImporter::Documents ScreenplayCeltxImporter::importDocuments( } case TextParagraphType::Character: { - if (!_options.importCharacters) { + if (!_options->importCharacters) { break; } @@ -133,19 +133,19 @@ AbstractScreenplayImporter::Documents ScreenplayCeltxImporter::importDocuments( } QVector ScreenplayCeltxImporter::importScreenplays( - const ScreenplayImportOptions& _options) const + const ScreenplayImportOptions* _options) const { - if (_options.importText == false) { + if (_options->importText == false) { return {}; } Screenplay result; - result.name = QFileInfo(_options.filePath).completeBaseName(); + result.name = QFileInfo(_options->filePath).completeBaseName(); // // Открываем файл // - const auto scriptHtml = readScript(_options.filePath); + const auto scriptHtml = readScript(_options->filePath); if (scriptHtml.isEmpty()) { return { result }; } diff --git a/src/corelib/business_layer/import/screenplay/screenplay_celtx_importer.h b/src/corelib/business_layer/import/screenplay/screenplay_celtx_importer.h index 30747eb43..5f8f7fdb0 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_celtx_importer.h +++ b/src/corelib/business_layer/import/screenplay/screenplay_celtx_importer.h @@ -16,12 +16,12 @@ class CORE_LIBRARY_EXPORT ScreenplayCeltxImporter : public AbstractScreenplayImp /** * @brief Импорт докуметов (всех, кроме сценариев) */ - Documents importDocuments(const ImportOptions& _options) const override; + Documents importDocuments(const ImportOptions* _options) const override; /** * @brief Сформировать xml-сценария во внутреннем формате */ - QVector importScreenplays(const ScreenplayImportOptions& _options) const override; + QVector importScreenplays(const ScreenplayImportOptions* _options) const override; }; } // namespace BusinessLayer diff --git a/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.cpp b/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.cpp index 4cd0595e2..819e548e4 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.cpp +++ b/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.cpp @@ -31,19 +31,19 @@ ScreenplayDocxImporter::~ScreenplayDocxImporter() = default; QVector ScreenplayDocxImporter::importScreenplays( - const ScreenplayImportOptions& _options) const + const ScreenplayImportOptions* _options) const { Screenplay screenplay; - screenplay.name = QFileInfo(_options.filePath).completeBaseName(); + screenplay.name = QFileInfo(_options->filePath).completeBaseName(); - if (_options.importText == false) { + if (_options->importText == false) { return { screenplay }; } // // Преобразуем заданный документ в QTextDocument и парсим его // - if (QTextDocument document; documentForImport(_options.filePath, document)) { + if (QTextDocument document; documentForImport(_options->filePath, document)) { screenplay.text = parseDocument(_options, document); } @@ -114,10 +114,10 @@ void ScreenplayDocxImporter::writeReviewMarks(QXmlStreamWriter& _writer, QTextCu } } -bool ScreenplayDocxImporter::shouldKeepSceneNumbers(const ImportOptions& _options) const +bool ScreenplayDocxImporter::shouldKeepSceneNumbers(const ImportOptions* _options) const { - const auto& options = static_cast(_options); - return options.keepSceneNumbers; + const auto options = static_cast(_options); + return options->keepSceneNumbers; } QString ScreenplayDocxImporter::characterName(const QString& _text) const diff --git a/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.h b/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.h index 16c892603..ca422761d 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.h +++ b/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.h @@ -20,7 +20,7 @@ class CORE_LIBRARY_EXPORT ScreenplayDocxImporter : public AbstractScreenplayImpo /** * @brief Сформировать xml-сценария во внутреннем формате */ - QVector importScreenplays(const ScreenplayImportOptions& _options) const override; + QVector importScreenplays(const ScreenplayImportOptions* _options) const override; protected: /** @@ -37,7 +37,7 @@ class CORE_LIBRARY_EXPORT ScreenplayDocxImporter : public AbstractScreenplayImpo /** * @brief Следует ли сохранять номера сцен */ - bool shouldKeepSceneNumbers(const ImportOptions& _options) const override; + bool shouldKeepSceneNumbers(const ImportOptions* _options) const override; /** * @brief Получить имя персонажа diff --git a/src/corelib/business_layer/import/screenplay/screenplay_fdx_importer.cpp b/src/corelib/business_layer/import/screenplay/screenplay_fdx_importer.cpp index 32eaf3cf0..f7c9974b4 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_fdx_importer.cpp +++ b/src/corelib/business_layer/import/screenplay/screenplay_fdx_importer.cpp @@ -20,12 +20,12 @@ namespace BusinessLayer { AbstractScreenplayImporter::Documents ScreenplayFdxImporter::importDocuments( - const ImportOptions& _options) const + const ImportOptions* _options) const { // // Открываем файл // - QFile fdxFile(_options.filePath); + QFile fdxFile(_options->filePath); if (!fdxFile.open(QIODevice::ReadOnly)) { return {}; } @@ -82,7 +82,7 @@ AbstractScreenplayImporter::Documents ScreenplayFdxImporter::importDocuments( switch (blockType) { case TextParagraphType::SceneHeading: { - if (!_options.importLocations) { + if (!_options->importLocations) { break; } @@ -96,7 +96,7 @@ AbstractScreenplayImporter::Documents ScreenplayFdxImporter::importDocuments( } case TextParagraphType::Character: { - if (!_options.importCharacters) { + if (!_options->importCharacters) { break; } @@ -131,19 +131,19 @@ AbstractScreenplayImporter::Documents ScreenplayFdxImporter::importDocuments( } QVector ScreenplayFdxImporter::importScreenplays( - const ScreenplayImportOptions& _options) const + const ScreenplayImportOptions* _options) const { - if (_options.importText == false) { + if (_options->importText == false) { return {}; } Screenplay result; - result.name = QFileInfo(_options.filePath).completeBaseName(); + result.name = QFileInfo(_options->filePath).completeBaseName(); // // Открываем файл // - QFile fdxFile(_options.filePath); + QFile fdxFile(_options->filePath); if (!fdxFile.open(QIODevice::ReadOnly)) { return { result }; } diff --git a/src/corelib/business_layer/import/screenplay/screenplay_fdx_importer.h b/src/corelib/business_layer/import/screenplay/screenplay_fdx_importer.h index 366f82f6f..a07b63b2e 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_fdx_importer.h +++ b/src/corelib/business_layer/import/screenplay/screenplay_fdx_importer.h @@ -16,12 +16,12 @@ class CORE_LIBRARY_EXPORT ScreenplayFdxImporter : public AbstractScreenplayImpor /** * @brief Импорт докуметов (всех, кроме сценариев) */ - Documents importDocuments(const ImportOptions& _options) const override; + Documents importDocuments(const ImportOptions* _options) const override; /** * @brief Сформировать xml-сценария во внутреннем формате */ - QVector importScreenplays(const ScreenplayImportOptions& _options) const override; + QVector importScreenplays(const ScreenplayImportOptions* _options) const override; }; } // namespace BusinessLayer diff --git a/src/corelib/business_layer/import/screenplay/screenplay_fountain_importer.cpp b/src/corelib/business_layer/import/screenplay/screenplay_fountain_importer.cpp index 7468bde16..5ade3418f 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_fountain_importer.cpp +++ b/src/corelib/business_layer/import/screenplay/screenplay_fountain_importer.cpp @@ -43,16 +43,16 @@ ScreenplayFountainImporter::ScreenplayFountainImporter() ScreenplayFountainImporter::~ScreenplayFountainImporter() = default; QVector ScreenplayFountainImporter::importScreenplays( - const ScreenplayImportOptions& _options) const + const ScreenplayImportOptions* _options) const { - if (_options.importText == false) { + if (_options->importText == false) { return {}; } // // Открываем файл // - QFile fountainFile(_options.filePath); + QFile fountainFile(_options->filePath); if (!fountainFile.open(QIODevice::ReadOnly)) { return {}; } @@ -60,9 +60,9 @@ QVector ScreenplayFountainImporter::impo // // Импортируем // - auto screenplay = screenplayText(fountainFile.readAll(), _options.keepSceneNumbers); + auto screenplay = screenplayText(fountainFile.readAll(), _options->keepSceneNumbers); if (screenplay.name.isEmpty()) { - screenplay.name = QFileInfo(_options.filePath).completeBaseName(); + screenplay.name = QFileInfo(_options->filePath).completeBaseName(); } return { screenplay }; diff --git a/src/corelib/business_layer/import/screenplay/screenplay_fountain_importer.h b/src/corelib/business_layer/import/screenplay/screenplay_fountain_importer.h index 4a691ddcd..b9a4a689b 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_fountain_importer.h +++ b/src/corelib/business_layer/import/screenplay/screenplay_fountain_importer.h @@ -41,7 +41,7 @@ class CORE_LIBRARY_EXPORT ScreenplayFountainImporter : public AbstractScreenplay /** * @brief Импортировать сценарии */ - QVector importScreenplays(const ScreenplayImportOptions& _options) const override; + QVector importScreenplays(const ScreenplayImportOptions* _options) const override; /** * @brief Получить основной текст сценария в формате xml из заданного текста diff --git a/src/corelib/business_layer/import/screenplay/screenplay_kit_scenarist_importer.cpp b/src/corelib/business_layer/import/screenplay/screenplay_kit_scenarist_importer.cpp index fb9679dd1..27a829834 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_kit_scenarist_importer.cpp +++ b/src/corelib/business_layer/import/screenplay/screenplay_kit_scenarist_importer.cpp @@ -533,14 +533,14 @@ ScreenplayKitScenaristImporter::ScreenplayKitScenaristImporter() ScreenplayKitScenaristImporter::~ScreenplayKitScenaristImporter() = default; AbstractScreenplayImporter::Documents ScreenplayKitScenaristImporter::importDocuments( - const ImportOptions& _options) const + const ImportOptions* _options) const { - const auto& options = static_cast(_options); + const auto& options = static_cast(_options); Documents result; { QSqlDatabase database = QSqlDatabase::addDatabase(kSqlDriver, kConnectionName); - database.setDatabaseName(options.filePath); + database.setDatabaseName(options->filePath); if (database.open()) { auto typeFor = [](const QSqlQuery& _record) { switch (_record.value("type").toUInt()) { @@ -574,7 +574,7 @@ AbstractScreenplayImporter::Documents ScreenplayKitScenaristImporter::importDocu // // Загрузим данные о персонажах // - if (options.importCharacters) { + if (options->importCharacters) { QSqlQuery charactersQuery(database); charactersQuery.prepare( "SELECT name, description FROM research WHERE type = ? ORDER by sort_order"); @@ -591,7 +591,7 @@ AbstractScreenplayImporter::Documents ScreenplayKitScenaristImporter::importDocu // // Загрузим данные о локациях // - if (options.importLocations) { + if (options->importLocations) { QSqlQuery locationsQuery(database); locationsQuery.prepare("SELECT * FROM research WHERE type = ? ORDER by sort_order"); locationsQuery.addBindValue(Location); @@ -607,7 +607,7 @@ AbstractScreenplayImporter::Documents ScreenplayKitScenaristImporter::importDocu // // Загрузим данные разработки // - if (options.importResearch) { + if (options->importResearch) { QSqlQuery documentsQuery(database); documentsQuery.prepare("SELECT * FROM research WHERE type IN (?, ?) ORDER BY " "parent_id, sort_order"); @@ -662,9 +662,9 @@ AbstractScreenplayImporter::Documents ScreenplayKitScenaristImporter::importDocu } QVector ScreenplayKitScenaristImporter::importScreenplays( - const ScreenplayImportOptions& _options) const + const ScreenplayImportOptions* _options) const { - if (_options.importText == false) { + if (_options->importText == false) { return {}; } @@ -672,14 +672,14 @@ QVector ScreenplayKitScenaristImporter:: { QSqlDatabase database = QSqlDatabase::addDatabase(kSqlDriver, kConnectionName); - database.setDatabaseName(_options.filePath); + database.setDatabaseName(_options->filePath); if (database.open()) { QSqlQuery query(database); // // Читаем сценарий (scenario - текст сценария) // - QString screenplayName = QFileInfo(_options.filePath).completeBaseName(); + QString screenplayName = QFileInfo(_options->filePath).completeBaseName(); { query.exec("SELECT text FROM scenario WHERE is_draft = 0"); query.next(); diff --git a/src/corelib/business_layer/import/screenplay/screenplay_kit_scenarist_importer.h b/src/corelib/business_layer/import/screenplay/screenplay_kit_scenarist_importer.h index b5d1514a6..2b4587c5f 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_kit_scenarist_importer.h +++ b/src/corelib/business_layer/import/screenplay/screenplay_kit_scenarist_importer.h @@ -19,12 +19,12 @@ class CORE_LIBRARY_EXPORT ScreenplayKitScenaristImporter : public AbstractScreen /** * @brief Импорт докуметов (всех, кроме сценариев) */ - Documents importDocuments(const ImportOptions& _options) const override; + Documents importDocuments(const ImportOptions* _options) const override; /** * @brief Сформировать xml-сценария во внутреннем формате */ - QVector importScreenplays(const ScreenplayImportOptions& _options) const override; + QVector importScreenplays(const ScreenplayImportOptions* _options) const override; private: class Implementation; diff --git a/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.cpp b/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.cpp index d91448ef9..fec7c4d99 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.cpp +++ b/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.cpp @@ -26,19 +26,19 @@ ScreenplayPdfImporter::~ScreenplayPdfImporter() = default; QVector ScreenplayPdfImporter::importScreenplays( - const ScreenplayImportOptions& _options) const + const ScreenplayImportOptions* _options) const { Screenplay screenplay; - screenplay.name = QFileInfo(_options.filePath).completeBaseName(); + screenplay.name = QFileInfo(_options->filePath).completeBaseName(); - if (_options.importText == false) { + if (_options->importText == false) { return { screenplay }; } // // Преобразуем заданный документ в QTextDocument и парсим его // - if (QTextDocument document; documentForImport(_options.filePath, document)) { + if (QTextDocument document; documentForImport(_options->filePath, document)) { screenplay.text = parseDocument(_options, document); } @@ -99,10 +99,10 @@ void ScreenplayPdfImporter::writeReviewMarks(QXmlStreamWriter& _writer, QTextCur } } -bool ScreenplayPdfImporter::shouldKeepSceneNumbers(const ImportOptions& _options) const +bool ScreenplayPdfImporter::shouldKeepSceneNumbers(const ImportOptions* _options) const { - const auto& options = static_cast(_options); - return options.keepSceneNumbers; + const auto options = static_cast(_options); + return options->keepSceneNumbers; } QString ScreenplayPdfImporter::characterName(const QString& _text) const diff --git a/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.h b/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.h index ea320bb2a..55b026889 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.h +++ b/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.h @@ -18,7 +18,7 @@ class CORE_LIBRARY_EXPORT ScreenplayPdfImporter : public AbstractScreenplayImpor /** * @brief Импортировать сценарии */ - QVector importScreenplays(const ScreenplayImportOptions& _options) const override; + QVector importScreenplays(const ScreenplayImportOptions* _options) const override; protected: /** @@ -35,7 +35,7 @@ class CORE_LIBRARY_EXPORT ScreenplayPdfImporter : public AbstractScreenplayImpor /** * @brief Следует ли сохранять номера сцен */ - bool shouldKeepSceneNumbers(const ImportOptions& _options) const override; + bool shouldKeepSceneNumbers(const ImportOptions* _options) const override; /** * @brief Получить имя персонажа diff --git a/src/corelib/business_layer/import/screenplay/screenplay_trelby_importer.cpp b/src/corelib/business_layer/import/screenplay/screenplay_trelby_importer.cpp index 347cc8ae4..8d9dd1e03 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_trelby_importer.cpp +++ b/src/corelib/business_layer/import/screenplay/screenplay_trelby_importer.cpp @@ -17,12 +17,12 @@ namespace BusinessLayer { AbstractScreenplayImporter::Documents ScreenplayTrelbyImporter::importDocuments( - const ImportOptions& _options) const + const ImportOptions* _options) const { // // Открываем файл // - QFile trelbyFile(_options.filePath); + QFile trelbyFile(_options->filePath); if (!trelbyFile.open(QIODevice::ReadOnly)) { return {}; } @@ -69,7 +69,7 @@ AbstractScreenplayImporter::Documents ScreenplayTrelbyImporter::importDocuments( if (paragraphType.startsWith(".")) { switch (blockType) { case TextParagraphType::SceneHeading: { - if (!_options.importLocations) { + if (!_options->importLocations) { break; } @@ -83,7 +83,7 @@ AbstractScreenplayImporter::Documents ScreenplayTrelbyImporter::importDocuments( } case TextParagraphType::Character: { - if (!_options.importCharacters) { + if (!_options->importCharacters) { break; } @@ -119,19 +119,19 @@ AbstractScreenplayImporter::Documents ScreenplayTrelbyImporter::importDocuments( } QVector ScreenplayTrelbyImporter::importScreenplays( - const ScreenplayImportOptions& _options) const + const ScreenplayImportOptions* _options) const { - if (_options.importText == false) { + if (_options->importText == false) { return {}; } Screenplay result; - result.name = QFileInfo(_options.filePath).completeBaseName(); + result.name = QFileInfo(_options->filePath).completeBaseName(); // // Открываем файл // - QFile trelbyFile(_options.filePath); + QFile trelbyFile(_options->filePath); if (!trelbyFile.open(QIODevice::ReadOnly)) { return { result }; } diff --git a/src/corelib/business_layer/import/screenplay/screenplay_trelby_importer.h b/src/corelib/business_layer/import/screenplay/screenplay_trelby_importer.h index 1e4af2488..83c3c335a 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_trelby_importer.h +++ b/src/corelib/business_layer/import/screenplay/screenplay_trelby_importer.h @@ -16,12 +16,12 @@ class CORE_LIBRARY_EXPORT ScreenplayTrelbyImporter : public AbstractScreenplayIm /** * @brief Импорт докуметов (всех, кроме сценариев) */ - Documents importDocuments(const ImportOptions& _options) const override; + Documents importDocuments(const ImportOptions* _options) const override; /** * @brief Сформировать xml-сценария во внутреннем формате */ - QVector importScreenplays(const ScreenplayImportOptions& _options) const override; + QVector importScreenplays(const ScreenplayImportOptions* _options) const override; }; } // namespace BusinessLayer diff --git a/src/corelib/business_layer/import/stageplay/abstract_stageplay_importer.h b/src/corelib/business_layer/import/stageplay/abstract_stageplay_importer.h index 3080d4c30..938320217 100644 --- a/src/corelib/business_layer/import/stageplay/abstract_stageplay_importer.h +++ b/src/corelib/business_layer/import/stageplay/abstract_stageplay_importer.h @@ -28,7 +28,7 @@ class CORE_LIBRARY_EXPORT AbstractStageplayImporter : virtual public AbstractImp /** * @brief Импорт пьесы из заданного документа */ - virtual Stageplay importStageplay(const ImportOptions& _options) const = 0; + virtual Stageplay importStageplay(const ImportOptions* _options) const = 0; }; } // namespace BusinessLayer diff --git a/src/corelib/business_layer/import/stageplay/stageplay_fountain_importer.cpp b/src/corelib/business_layer/import/stageplay/stageplay_fountain_importer.cpp index 65afbe59a..c1fd03305 100644 --- a/src/corelib/business_layer/import/stageplay/stageplay_fountain_importer.cpp +++ b/src/corelib/business_layer/import/stageplay/stageplay_fountain_importer.cpp @@ -41,16 +41,16 @@ StageplayFountainImporter::StageplayFountainImporter() StageplayFountainImporter::~StageplayFountainImporter() = default; AbstractStageplayImporter::Stageplay StageplayFountainImporter::importStageplay( - const ImportOptions& _options) const + const ImportOptions* _options) const { - if (_options.importText == false) { + if (_options->importText == false) { return {}; } // // Открываем файл // - QFile fountainFile(_options.filePath); + QFile fountainFile(_options->filePath); if (!fountainFile.open(QIODevice::ReadOnly)) { return {}; } @@ -60,7 +60,7 @@ AbstractStageplayImporter::Stageplay StageplayFountainImporter::importStageplay( // auto stageplay = stageplayText(fountainFile.readAll()); if (stageplay.name.isEmpty()) { - stageplay.name = QFileInfo(_options.filePath).completeBaseName(); + stageplay.name = QFileInfo(_options->filePath).completeBaseName(); } return stageplay; diff --git a/src/corelib/business_layer/import/stageplay/stageplay_fountain_importer.h b/src/corelib/business_layer/import/stageplay/stageplay_fountain_importer.h index e064279e2..d31a6019d 100644 --- a/src/corelib/business_layer/import/stageplay/stageplay_fountain_importer.h +++ b/src/corelib/business_layer/import/stageplay/stageplay_fountain_importer.h @@ -41,7 +41,7 @@ class CORE_LIBRARY_EXPORT StageplayFountainImporter : public AbstractStageplayIm /** * @brief Импортировать пьесу */ - Stageplay importStageplay(const ImportOptions& _options) const override; + Stageplay importStageplay(const ImportOptions* _options) const override; /** * @brief Получить основной текст пьесы в формате xml из заданного текста