From 7936873cd3190a96ae197097a91bb41a679d58e9 Mon Sep 17 00:00:00 2001 From: Ilya Putilin Date: Mon, 2 Sep 2024 22:07:21 +0700 Subject: [PATCH] Import documents from PDF Add import characters and locations from PDF --- .../import/abstract_document_importer.cpp | 280 ++++++++++++++---- .../import/abstract_document_importer.h | 40 ++- .../screenplay/screenplay_docx_importer.cpp | 215 ++------------ .../screenplay/screenplay_docx_importer.h | 28 +- .../screenplay/screenplay_pdf_importer.cpp | 61 ++-- .../screenplay/screenplay_pdf_importer.h | 25 +- 6 files changed, 364 insertions(+), 285 deletions(-) diff --git a/src/corelib/business_layer/import/abstract_document_importer.cpp b/src/corelib/business_layer/import/abstract_document_importer.cpp index 0872e3164..aee243a05 100644 --- a/src/corelib/business_layer/import/abstract_document_importer.cpp +++ b/src/corelib/business_layer/import/abstract_document_importer.cpp @@ -8,8 +8,11 @@ #include #include +#include #include +#include + namespace BusinessLayer { @@ -21,6 +24,12 @@ namespace { const QRegularExpression kPlaceContainsChecker( "^(INT|EXT|INT/EXT|ИНТ|НАТ|ИНТ/НАТ|ПАВ|ЭКСТ|ИНТ/ЭКСТ)([.]|[ - ])"); +/** + * @brief Регулярное выражение для определения строки, начинающейся с номера + */ +const QRegularExpression kStartFromNumberChecker( + "^([\\d]{1,}[\\d\\S]{0,})([.]|[-])(([\\d\\S]{1,})([.]|)|) "); + /** * @brief Регулярное выражение для определения блока "Титр" по наличию ключевых слов */ @@ -66,6 +75,138 @@ AbstractDocumentImporter::AbstractDocumentImporter() AbstractDocumentImporter::~AbstractDocumentImporter() = default; +AbstractImporter::Documents AbstractDocumentImporter::importDocuments( + const ImportOptions& _options) const +{ + // + // Преобразовать заданный документ в QTextDocument + // + QTextDocument document; + const bool documentDone = documentForImport(_options.filePath, document); + if (!documentDone) { + return {}; + } + + // + // Найти минимальный отступ слева для всех блоков + // ЗАЧЕМ: во многих программах (Final Draft, Screeviner) сделано так, что поля + // задаются за счёт оступов. Получается что и заглавие сцены и описание действия + // имеют отступы. Так вот это и будет минимальным отступом, который не будем считать + // + int minLeftMargin = 1000; + { + QTextCursor cursor(&document); + while (!cursor.atEnd()) { + if (minLeftMargin > cursor.blockFormat().leftMargin()) { + minLeftMargin = std::max(0.0, cursor.blockFormat().leftMargin()); + } + + cursor.movePosition(QTextCursor::NextBlock); + cursor.movePosition(QTextCursor::EndOfBlock); + } + } + + QTextCursor cursor(&document); + + // + // Для каждого блока текста определяем тип + // + // ... последний стиль блока + auto lastBlockType = TextParagraphType::Undefined; + // ... количество пустых строк + int emptyLines = 0; + std::set characterNames; + std::set locationNames; + do { + cursor.movePosition(QTextCursor::EndOfBlock); + + // + // Если в блоке есть текст + // + if (!cursor.block().text().simplified().isEmpty()) { + // + // ... определяем тип + // + const auto blockType + = typeForTextCursor(cursor, lastBlockType, emptyLines, minLeftMargin); + QString paragraphText = cursor.block().text().simplified(); + + // + // Если текущий тип "Время и место", то удалим номер сцены + // + if (blockType == TextParagraphType::SceneHeading) { + paragraphText = TextHelper::smartToUpper(paragraphText); + const auto match = kStartFromNumberChecker.match(paragraphText); + if (match.hasMatch()) { + paragraphText = paragraphText.mid(match.capturedEnd()); + } + } + + // + // Выполняем корректировки + // + paragraphText = clearBlockText(blockType, paragraphText); + + switch (blockType) { + case TextParagraphType::SceneHeading: { + if (!_options.importLocations) { + break; + } + + const auto currentLocationName = locationName(paragraphText); + if (currentLocationName.isEmpty()) { + break; + } + + locationNames.emplace(currentLocationName); + break; + } + + case TextParagraphType::Character: { + if (!_options.importCharacters) { + break; + } + + const auto currentCharacterName = characterName(paragraphText); + if (currentCharacterName.isEmpty()) { + break; + } + + characterNames.emplace(currentCharacterName); + break; + } + + default: + break; + } + + // + // Запомним последний стиль блока и обнулим счётчик пустых строк + // + lastBlockType = blockType; + emptyLines = 0; + } + // + // Если в блоке нет текста, то увеличиваем счётчик пустых строк + // + else { + ++emptyLines; + } + + cursor.movePosition(QTextCursor::NextCharacter); + } while (!cursor.atEnd()); + + Documents documents; + for (const auto& characterName : characterNames) { + documents.characters.append( + { Domain::DocumentObjectType::Character, characterName, {}, {} }); + } + for (const auto& locationName : locationNames) { + documents.locations.append({ Domain::DocumentObjectType::Location, locationName, {}, {} }); + } + return documents; +} + QString AbstractDocumentImporter::parseDocument(const ImportOptions& _options, QTextDocument& _document) const { @@ -118,11 +259,27 @@ QString AbstractDocumentImporter::parseDocument(const ImportOptions& _options, = typeForTextCursor(cursor, lastBlockType, emptyLines, minLeftMargin); // - // Обработаем блок заголовка сцены в наследниках + // Извлечем номер сцены // QString sceneNumber; if (blockType == TextParagraphType::SceneHeading) { - sceneNumber = extractSceneNumber(_options, cursor); + const auto match + = kStartFromNumberChecker.match(cursor.block().text().simplified()); + if (match.hasMatch()) { + cursor.movePosition(QTextCursor::StartOfBlock); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, + match.capturedEnd()); + if (cursor.hasSelection()) { + if (shouldKeepSceneNumbers(_options)) { + sceneNumber = cursor.selectedText().trimmed(); + if (sceneNumber.endsWith('.')) { + sceneNumber.chop(1); + } + } + cursor.deleteChar(); + } + cursor.movePosition(QTextCursor::EndOfBlock); + } } // @@ -218,60 +375,6 @@ QString AbstractDocumentImporter::parseDocument(const ImportOptions& _options, return { result }; } -QString AbstractDocumentImporter::clearBlockText(TextParagraphType _blockType, - const QString& _blockText) const -{ - QString result = _blockText; - - // - // Удаляем длинные тире - // - result = result.replace("–", "-"); - - // - // Для блока заголовка сцены: - // * всевозможные "инт - " меняем на "инт. " - // * убираем точки в конце названия локации - // - if (_blockType == TextParagraphType::SceneHeading) { - const QString location = /*ScreenplaySceneHeadingParser::location*/ (_blockText); - QString clearLocation = location.simplified(); - clearLocation.remove(NOISE_AT_START); - clearLocation.remove(NOISE_AT_END); - if (location != clearLocation) { - result = result.replace(location, clearLocation); - } - } - // - // Для персонажей - // * убираем точки в конце - // - else if (_blockType == TextParagraphType::Character) { - const QString name = /*ScreenplayCharacterParser::name*/ (_blockText); - QString clearName = name.simplified(); - clearName.remove(NOISE_AT_END); - if (name != clearName) { - result = result.replace(name, clearName); - } - } - // - // Ремарка - // * убираем скобки - // - else if (_blockType == TextParagraphType::Parenthetical) { - QString clearParenthetical = _blockText.simplified(); - if (!clearParenthetical.isEmpty() && clearParenthetical.front() == '(') { - clearParenthetical.remove(0, 1); - } - if (!clearParenthetical.isEmpty() && clearParenthetical.back() == ')') { - clearParenthetical.chop(1); - } - result = clearParenthetical; - } - - return result; -} - TextParagraphType AbstractDocumentImporter::typeForTextCursor(const QTextCursor& _cursor, TextParagraphType _lastBlockType, int _prevEmptyLines, @@ -418,13 +521,70 @@ TextParagraphType AbstractDocumentImporter::typeForTextCursor(const QTextCursor& return blockType; } -QString AbstractDocumentImporter::extractSceneNumber(const ImportOptions& _options, - QTextCursor& _cursor) const +QString AbstractDocumentImporter::clearBlockText(TextParagraphType _blockType, + const QString& _blockText) const +{ + QString result = _blockText; + + // + // Удаляем длинные тире + // + result = result.replace("–", "-"); + + // + // Для блока заголовка сцены: + // * всевозможные "инт - " меняем на "инт. " + // * убираем точки в конце названия локации + // + if (_blockType == TextParagraphType::SceneHeading) { + const QString location = /*ScreenplaySceneHeadingParser::location*/ (_blockText); + QString clearLocation = location.simplified(); + clearLocation.remove(NOISE_AT_START); + clearLocation.remove(NOISE_AT_END); + if (location != clearLocation) { + result = result.replace(location, clearLocation); + } + } + // + // Для персонажей + // * убираем точки в конце + // + else if (_blockType == TextParagraphType::Character) { + const QString name = /*ScreenplayCharacterParser::name*/ (_blockText); + QString clearName = name.simplified(); + clearName.remove(NOISE_AT_END); + if (name != clearName) { + result = result.replace(name, clearName); + } + } + // + // Ремарка + // * убираем скобки + // + else if (_blockType == TextParagraphType::Parenthetical) { + QString clearParenthetical = _blockText.simplified(); + if (!clearParenthetical.isEmpty() && clearParenthetical.front() == '(') { + clearParenthetical.remove(0, 1); + } + if (!clearParenthetical.isEmpty() && clearParenthetical.back() == ')') { + clearParenthetical.chop(1); + } + result = clearParenthetical; + } + + return result; +} + +QRegularExpression AbstractDocumentImporter::startFromNumberChecker() const +{ + return kStartFromNumberChecker; +} + +bool AbstractDocumentImporter::shouldKeepSceneNumbers(const ImportOptions& _options) const { Q_UNUSED(_options) - Q_UNUSED(_cursor) - return QString(); + return false; } void AbstractDocumentImporter::writeReviewMarks(QXmlStreamWriter& _writer, diff --git a/src/corelib/business_layer/import/abstract_document_importer.h b/src/corelib/business_layer/import/abstract_document_importer.h index bf752a568..c7d62dc64 100644 --- a/src/corelib/business_layer/import/abstract_document_importer.h +++ b/src/corelib/business_layer/import/abstract_document_importer.h @@ -1,5 +1,7 @@ #pragma once +#include "abstract_importer.h" + #include class QTextDocument; @@ -15,11 +17,16 @@ enum class TextParagraphType; /** * @brief Класс для импорта из QTextDocument */ -class CORE_LIBRARY_EXPORT AbstractDocumentImporter +class CORE_LIBRARY_EXPORT AbstractDocumentImporter : virtual public AbstractImporter { public: AbstractDocumentImporter(); - virtual ~AbstractDocumentImporter(); + ~AbstractDocumentImporter() override; + + /** + * @brief Импорт докуметов (всех, кроме сценариев) + */ + Documents importDocuments(const ImportOptions& _options) const override; /** * @brief Получить из QTextDocument xml-строку @@ -28,9 +35,10 @@ class CORE_LIBRARY_EXPORT AbstractDocumentImporter protected: /** - * @brief Очистка блоков от мусора и их корректировки + * @brief Получить документ для импорта + * @return true, если получилось открыть заданный файл */ - QString clearBlockText(TextParagraphType _blockType, const QString& _blockText) const; + virtual bool documentForImport(const QString& _filePath, QTextDocument& _document) const = 0; /** * @brief Определить тип блока в текущей позиции курсора @@ -41,14 +49,34 @@ class CORE_LIBRARY_EXPORT AbstractDocumentImporter int _minLeftMargin) const; /** - * @brief Извлечь номер сцены из заголовка + * @brief Очистка блоков от мусора и их корректировки + */ + QString clearBlockText(TextParagraphType _blockType, const QString& _blockText) const; + + /** + * @brief Получить регулярное выражение для определения строки, начинающейся с номера */ - virtual QString extractSceneNumber(const ImportOptions& _options, QTextCursor& _cursor) const; + QRegularExpression startFromNumberChecker() const; + + /** + * @brief Следует ли сохранять номера сцен + */ + virtual bool shouldKeepSceneNumbers(const ImportOptions& _options) const; /** * @brief Записать редакторские заметки */ virtual void writeReviewMarks(QXmlStreamWriter& _writer, QTextCursor& _cursor) const; + + /** + * @brief Получить имя персонажа + */ + virtual QString characterName(const QString& _text) const = 0; + + /** + * @brief Получить название локации + */ + virtual QString locationName(const QString& _text) const = 0; }; 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 f263b6148..4cd0595e2 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.cpp +++ b/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -18,160 +17,18 @@ #include #include #include -#include namespace BusinessLayer { -namespace { - -/** - * @brief Регулярное выражение для определения блока "Время и место" по началу с номера - */ -const QRegularExpression kStartFromNumberChecker( - "^([\\d]{1,}[\\d\\S]{0,})([.]|[-])(([\\d\\S]{1,})([.]|)|) "); - -} // namespace - -AbstractScreenplayImporter::Documents ScreenplayDocxImporter::importDocuments( - const ImportOptions& _options) const +ScreenplayDocxImporter::ScreenplayDocxImporter() + : AbstractScreenplayImporter() + , AbstractDocumentImporter() { - // - // Открываем файл - // - QFile documentFile(_options.filePath); - if (!documentFile.open(QIODevice::ReadOnly)) { - return {}; - } - - // - // Преобразовать заданный документ в QTextDocument - // - QTextDocument documentForImport; - { - QScopedPointer reader(FormatManager::createReader(&documentFile)); - reader->read(&documentFile, &documentForImport); - } - - // - // Найти минимальный отступ слева для всех блоков - // ЗАЧЕМ: во многих программах (Final Draft, Screeviner) сделано так, что поля - // задаются за счёт оступов. Получается что и заглавие сцены и описание действия - // имеют отступы. Так вот это и будет минимальным отступом, который не будем считать - // - int minLeftMargin = 1000; - { - QTextCursor cursor(&documentForImport); - while (!cursor.atEnd()) { - if (minLeftMargin > cursor.blockFormat().leftMargin()) { - minLeftMargin = std::max(0.0, cursor.blockFormat().leftMargin()); - } - - cursor.movePosition(QTextCursor::NextBlock); - cursor.movePosition(QTextCursor::EndOfBlock); - } - } - - QTextCursor cursor(&documentForImport); - - // - // Для каждого блока текста определяем тип - // - // ... последний стиль блока - auto lastBlockType = TextParagraphType::Undefined; - // ... количество пустых строк - int emptyLines = 0; - std::set characterNames; - std::set locationNames; - do { - cursor.movePosition(QTextCursor::EndOfBlock); - - // - // Если в блоке есть текст - // - if (!cursor.block().text().simplified().isEmpty()) { - // - // ... определяем тип - // - const auto blockType - = typeForTextCursor(cursor, lastBlockType, emptyLines, minLeftMargin); - QString paragraphText = cursor.block().text().simplified(); - - // - // Если текущий тип "Время и место", то удалим номер сцены - // - if (blockType == TextParagraphType::SceneHeading) { - paragraphText = TextHelper::smartToUpper(paragraphText); - const auto match = kStartFromNumberChecker.match(paragraphText); - if (match.hasMatch()) { - paragraphText = paragraphText.mid(match.capturedEnd()); - } - } - - // - // Выполняем корректировки - // - paragraphText = clearBlockText(blockType, paragraphText); - - switch (blockType) { - case TextParagraphType::SceneHeading: { - if (!_options.importLocations) { - break; - } - - const auto locationName = ScreenplaySceneHeadingParser::location(paragraphText); - if (locationName.isEmpty()) { - break; - } - - locationNames.emplace(locationName); - break; - } - - case TextParagraphType::Character: { - if (!_options.importCharacters) { - break; - } - - const auto characterName = ScreenplayCharacterParser::name(paragraphText); - if (characterName.isEmpty()) { - break; - } - - characterNames.emplace(characterName); - break; - } - - default: - break; - } - - // - // Запомним последний стиль блока и обнулим счётчик пустых строк - // - lastBlockType = blockType; - emptyLines = 0; - } - // - // Если в блоке нет текста, то увеличиваем счётчик пустых строк - // - else { - ++emptyLines; - } +} - cursor.movePosition(QTextCursor::NextCharacter); - } while (!cursor.atEnd()); +ScreenplayDocxImporter::~ScreenplayDocxImporter() = default; - Documents documents; - for (const auto& characterName : characterNames) { - documents.characters.append( - { Domain::DocumentObjectType::Character, characterName, {}, {} }); - } - for (const auto& locationName : locationNames) { - documents.locations.append({ Domain::DocumentObjectType::Location, locationName, {}, {} }); - } - return documents; -} QVector ScreenplayDocxImporter::importScreenplays( const ScreenplayImportOptions& _options) const @@ -184,49 +41,25 @@ QVector ScreenplayDocxImporter::importSc } // - // Открываем файл - // - QFile documentFile(_options.filePath); - if (!documentFile.open(QIODevice::ReadOnly)) { - return { screenplay }; - } - - // - // Преобразовать заданный документ в QTextDocument + // Преобразуем заданный документ в QTextDocument и парсим его // - QTextDocument documentForImport; - { - QScopedPointer reader(FormatManager::createReader(&documentFile)); - reader->read(&documentFile, &documentForImport); + if (QTextDocument document; documentForImport(_options.filePath, document)) { + screenplay.text = parseDocument(_options, document); } - screenplay.text = parseDocument(_options, documentForImport); - return { screenplay }; } -QString ScreenplayDocxImporter::extractSceneNumber(const ImportOptions& _options, - QTextCursor& _cursor) const +bool ScreenplayDocxImporter::documentForImport(const QString& _filePath, + QTextDocument& _document) const { - QString sceneNumber; - const auto match = kStartFromNumberChecker.match(_cursor.block().text().simplified()); - if (match.hasMatch()) { - _cursor.movePosition(QTextCursor::StartOfBlock); - _cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, - match.capturedEnd()); - if (_cursor.hasSelection()) { - const auto& options = static_cast(_options); - if (options.keepSceneNumbers) { - sceneNumber = _cursor.selectedText().trimmed(); - if (sceneNumber.endsWith('.')) { - sceneNumber.chop(1); - } - } - _cursor.deleteChar(); - } - _cursor.movePosition(QTextCursor::EndOfBlock); + QFile documentFile(_filePath); + if (documentFile.open(QIODevice::ReadOnly)) { + QScopedPointer reader(FormatManager::createReader(&documentFile)); + reader->read(&documentFile, &_document); + return true; } - return sceneNumber; + return false; } void ScreenplayDocxImporter::writeReviewMarks(QXmlStreamWriter& _writer, QTextCursor& _cursor) const @@ -281,4 +114,20 @@ void ScreenplayDocxImporter::writeReviewMarks(QXmlStreamWriter& _writer, QTextCu } } +bool ScreenplayDocxImporter::shouldKeepSceneNumbers(const ImportOptions& _options) const +{ + const auto& options = static_cast(_options); + return options.keepSceneNumbers; +} + +QString ScreenplayDocxImporter::characterName(const QString& _text) const +{ + return ScreenplayCharacterParser::name(_text); +} + +QString ScreenplayDocxImporter::locationName(const QString& _text) const +{ + return ScreenplaySceneHeadingParser::location(_text); +} + } // namespace BusinessLayer 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 f3bbfc0fb..16c892603 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.h +++ b/src/corelib/business_layer/import/screenplay/screenplay_docx_importer.h @@ -14,12 +14,8 @@ class CORE_LIBRARY_EXPORT ScreenplayDocxImporter : public AbstractScreenplayImpo public AbstractDocumentImporter { public: - ScreenplayDocxImporter() = default; - - /** - * @brief Импорт докуметов (всех, кроме сценариев) - */ - Documents importDocuments(const ImportOptions& _options) const override; + ScreenplayDocxImporter(); + ~ScreenplayDocxImporter() override; /** * @brief Сформировать xml-сценария во внутреннем формате @@ -28,14 +24,30 @@ class CORE_LIBRARY_EXPORT ScreenplayDocxImporter : public AbstractScreenplayImpo protected: /** - * @brief Извлечь номер сцены из заголовка + * @brief Получить документ для импорта + * @return true, если получилось открыть заданный файл */ - QString extractSceneNumber(const ImportOptions& _options, QTextCursor& _cursor) const override; + bool documentForImport(const QString& _filePath, QTextDocument& _document) const override; /** * @brief Записать редакторские заметки */ void writeReviewMarks(QXmlStreamWriter& _writer, QTextCursor& _cursor) const override; + + /** + * @brief Следует ли сохранять номера сцен + */ + bool shouldKeepSceneNumbers(const ImportOptions& _options) const override; + + /** + * @brief Получить имя персонажа + */ + QString characterName(const QString& _text) const override; + + /** + * @brief Получить название локации + */ + QString locationName(const QString& _text) const override; }; } // namespace BusinessLayer 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 d8668698d..e63ab223f 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.cpp +++ b/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.cpp @@ -3,6 +3,8 @@ #include "TableExtraction.h" #include "screenplay_import_options.h" +#include + #include #include @@ -18,13 +20,6 @@ ScreenplayPdfImporter::ScreenplayPdfImporter() ScreenplayPdfImporter::~ScreenplayPdfImporter() = default; -AbstractImporter::Documents ScreenplayPdfImporter::importDocuments( - const ImportOptions& _options) const -{ - Documents documents; - return documents; -} - QVector ScreenplayPdfImporter::importScreenplays( const ScreenplayImportOptions& _options) const { @@ -36,27 +31,45 @@ QVector ScreenplayPdfImporter::importScr } // - // Открываем файл + // Преобразуем заданный документ в QTextDocument и парсим его // - QFile fountainFile(_options.filePath); - if (!fountainFile.open(QIODevice::ReadOnly)) { - return {}; + if (QTextDocument document; documentForImport(_options.filePath, document)) { + screenplay.text = parseDocument(_options, document); } - // - // Преобразовать заданный документ в QTextDocument - // Используем TableExtraction, чтобы извлечь не только текст, но и линии - // - TableExtraction tableExtractor; - tableExtractor.ExtractTables(_options.filePath.toStdString(), 0, -1, true); - QTextDocument document; - tableExtractor.GetResultsAsDocument(document); - - // - // Парсим QTextDocument - // - screenplay.text = parseDocument(_options, document); return { screenplay }; } +bool ScreenplayPdfImporter::documentForImport(const QString& _filePath, + QTextDocument& _document) const +{ + QFile documentFile(_filePath); + if (documentFile.open(QIODevice::ReadOnly)) { + // + // Используем TableExtraction, чтобы извлечь не только текст, но и линии + // + TableExtraction tableExtractor; + tableExtractor.ExtractTables(_filePath.toStdString(), 0, -1, true); + tableExtractor.GetResultsAsDocument(_document); + return true; + } + return false; +} + +bool ScreenplayPdfImporter::shouldKeepSceneNumbers(const ImportOptions& _options) const +{ + const auto& options = static_cast(_options); + return options.keepSceneNumbers; +} + +QString ScreenplayPdfImporter::characterName(const QString& _text) const +{ + return ScreenplayCharacterParser::name(_text); +} + +QString ScreenplayPdfImporter::locationName(const QString& _text) const +{ + return ScreenplaySceneHeadingParser::location(_text); +} + } // namespace BusinessLayer 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 d77efce09..26aeccc47 100644 --- a/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.h +++ b/src/corelib/business_layer/import/screenplay/screenplay_pdf_importer.h @@ -16,14 +16,31 @@ class CORE_LIBRARY_EXPORT ScreenplayPdfImporter : public AbstractScreenplayImpor ~ScreenplayPdfImporter() override; /** - * @brief Импорт докуметов (всех, кроме сценариев) + * @brief Импортировать сценарии */ - Documents importDocuments(const ImportOptions& _options) const override; + QVector importScreenplays(const ScreenplayImportOptions& _options) const override; +protected: /** - * @brief Импортировать сценарии + * @brief Получить документ для импорта + * @return true, если получилось открыть заданный файл */ - QVector importScreenplays(const ScreenplayImportOptions& _options) const override; + bool documentForImport(const QString& _filePath, QTextDocument& _document) const override; + + /** + * @brief Следует ли сохранять номера сцен + */ + bool shouldKeepSceneNumbers(const ImportOptions& _options) const override; + + /** + * @brief Получить имя персонажа + */ + QString characterName(const QString& _text) const override; + + /** + * @brief Получить название локации + */ + QString locationName(const QString& _text) const override; }; } // namespace BusinessLayer