Skip to content

Commit 0f55669

Browse files
[FEATURE] 3D viewer selection (kitodo#1395)
Co-authored-by: Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
1 parent 1ff16c9 commit 0f55669

File tree

10 files changed

+155
-17
lines changed

10 files changed

+155
-17
lines changed

Classes/Configuration/UseGroupsConfiguration.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ private function __construct()
5656
'useGroupsDownload',
5757
'useGroupsFulltext',
5858
'useGroupsAudio',
59-
'useGroupsScore'
59+
'useGroupsScore',
60+
'useGroupsModel'
6061
];
6162

6263
foreach ($configKeys as $key) {
@@ -130,6 +131,18 @@ public function getImage(): array
130131
return $this->getByType('Image');
131132
}
132133

134+
/**
135+
* Get the configuration for 'Model' use groups type.
136+
*
137+
* @access public
138+
*
139+
* @return array
140+
*/
141+
public function getModel(): array
142+
{
143+
return $this->getByType('Model');
144+
}
145+
133146
/**
134147
* Get the configuration for 'Score' use groups type.
135148
*

Classes/Controller/ToolboxController.php

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@
1313

1414
use Kitodo\Dlf\Common\AbstractDocument;
1515
use Kitodo\Dlf\Common\Helper;
16+
use Kitodo\Dlf\Middleware\Embedded3dViewer;
1617
use Psr\Http\Message\ResponseInterface;
18+
use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader;
19+
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
20+
use TYPO3\CMS\Core\Resource\StorageRepository;
1721
use TYPO3\CMS\Core\Utility\GeneralUtility;
1822
use TYPO3\CMS\Core\Utility\MathUtility;
23+
use TYPO3\CMS\Core\Utility\PathUtility;
1924

2025
/**
2126
* Controller class for plugin 'Toolbox'.
@@ -113,6 +118,10 @@ private function renderTools(): void
113118
case 'scoretool':
114119
$this->renderToolByName('renderScoreTool');
115120
break;
121+
case 'tx_dlf_viewerselectiontool':
122+
case 'viewerselectiontool':
123+
$this->renderToolByName('renderViewerSelectionTool');
124+
break;
116125
default:
117126
$this->logger->warning('Incorrect tool configuration: "' . $this->settings['tools'] . '". Tool "' . $tool . '" does not exist.');
118127
}
@@ -135,6 +144,30 @@ private function renderToolByName(string $tool): void
135144
$this->view->assign($tool, true);
136145
}
137146

147+
/**
148+
* Get the URL of the model.
149+
*
150+
* Gets the URL of the model by parameter or from the configured file group of the document.
151+
*
152+
* @access private
153+
*
154+
* @return string
155+
*/
156+
private function getModelUrl(): string
157+
{
158+
$modelUrl = '';
159+
if (!empty($this->requestData['model'])) {
160+
$modelUrl = $this->requestData['model'];
161+
} elseif (!($this->isDocMissingOrEmpty() || empty($this->useGroupsConfiguration->getModel()))) {
162+
$this->setPage();
163+
if (isset($this->requestData['page'])) {
164+
$file = $this->getFile($this->requestData['page'], $this->useGroupsConfiguration->getModel());
165+
$modelUrl = $file['url'] ?? '';
166+
}
167+
}
168+
return $modelUrl;
169+
}
170+
138171
/**
139172
* Get the score file.
140173
*
@@ -370,19 +403,55 @@ private function renderImageManipulationTool(): void
370403
*/
371404
private function renderModelDownloadTool(): void
372405
{
373-
// TODO: missing fileGrpsModelDownload, should be added to ext config as useGroupsModelDownload
374-
if (
375-
$this->isDocMissingOrEmpty()
376-
|| empty($this->settings['fileGrpsModelDownload'])
377-
) {
378-
// Quit without doing anything if required variables are not set.
406+
$modelUrl = $this->getModelUrl();
407+
if ($modelUrl === '') {
408+
$this->logger->debug("Model URL could not be determined");
379409
return;
380410
}
411+
$this->view->assign('modelUrl', $modelUrl);
412+
}
381413

382-
$this->setPage();
383414

384-
if (isset($this->requestData['page'])) {
385-
$this->view->assign('modelDownload', $this->getFile($this->requestData['page'], GeneralUtility::trimExplode(',', $this->settings['fileGrpsModelDownload'])));
415+
/**
416+
* Renders the viewer selection tool
417+
* Renders the viewer selection tool (used in template)
418+
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
419+
*
420+
* @access private
421+
*
422+
* @return void
423+
* @throws InsufficientFolderAccessPermissionsException
424+
*/
425+
private function renderViewerSelectionTool(): void
426+
{
427+
$model = $this->getModelUrl();
428+
if (!$model) {
429+
$this->logger->debug("Model URL could not be determined");
430+
return;
431+
}
432+
433+
$pathInfo = PathUtility::pathinfo($model);
434+
$modelFormat = strtolower($pathInfo["extension"]);
435+
$viewers = [];
436+
/** @var StorageRepository $storageRepository */
437+
$storageRepository = GeneralUtility::makeInstance(StorageRepository::class);
438+
$defaultStorage = $storageRepository->getDefaultStorage();
439+
if ($defaultStorage->hasFolder(Embedded3dViewer::VIEWER_FOLDER)) {
440+
$viewerFolders = $defaultStorage->getFoldersInFolder($defaultStorage->getFolder(Embedded3dViewer::VIEWER_FOLDER));
441+
if (count($viewerFolders) > 0) {
442+
/** @var YamlFileLoader $yamlFileLoader */
443+
$yamlFileLoader = GeneralUtility::makeInstance(YamlFileLoader::class);
444+
foreach ($viewerFolders as $viewerFolder) {
445+
if ($viewerFolder->hasFile(Embedded3dViewer::VIEWER_CONFIG_YML)) {
446+
$fileIdentifier = $viewerFolder->getFile(Embedded3dViewer::VIEWER_CONFIG_YML)->getIdentifier();
447+
$viewerConfig = $yamlFileLoader->load($defaultStorage->getName() . $fileIdentifier)["viewer"];
448+
if (!empty($viewerConfig["supportedModelFormats"]) && in_array($modelFormat, array_map('strtolower', $viewerConfig["supportedModelFormats"]))) {
449+
$viewers[] = (object) ['id' => $viewerFolder->getName(), 'name' => $viewerConfig["name"] ?? $viewerFolder->getName()];
450+
}
451+
}
452+
}
453+
$this->view->assign('viewers', $viewers);
454+
}
386455
}
387456
}
388457

Documentation/Developers/Embedded3DViewer.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ On this page, you will find all the information needed to configure and embed an
1010
:local:
1111
:depth: 2
1212

13+
.. _Embedded 3D Viewer Setup:
14+
1315
Setup
1416
=======
1517

@@ -27,11 +29,13 @@ Configuration
2729

2830
By default, the viewers from the folder ``dlf_3d_viewers`` are all active and can be accessed and tested via URL.
2931

30-
For this, only the parameter ``tx_dlf[viewer]`` with the name of the viewer and the encoded URL to the model via the parameter ``tx_dlf[model]`` need to be passed to the URL under which the plugin ``plugin.tx_dlf_embedded3dViewer`` is rendered.
32+
For this, only the parameter ``tx_dlf[viewer]`` with the encoded subfolder name of the viewer needs to be passed to the URL where the plugin ``plugin.tx_dlf_embedded3dViewer`` is rendered.
3133

3234
.. note::
3335
For example in the DFG Viewer, this is the page whose ID is set via the constant ``config.kitodoPageView``.
3436

37+
To render the model, the encoded URL to the METS document should be set using the parameter ``tx_dlf[id]``. Alternatively, it is possible to define the model directly with an encoded URL via the parameter ``tx_dlf[model]``.
38+
3539
Automatic selection of the viewer
3640
-------
3741

Documentation/Plugins/Index.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,21 @@ The fulltext is fetched and rendered by JavaScript into the `<div id="tx-dlf-ful
10181018

10191019
**Please note**: To allow JavaScript fetching the fulltext, the `CORS headers <https://en.wikipedia.org/wiki/Cross-origin_resource_sharing>`_ must be configured appropriate on the providing webserver.
10201020

1021+
Model download tool
1022+
^^^^^^^^^^^^^
1023+
1024+
This tool makes it possible to extract the model URL from the METS file or use the provided model parameter to provide a download URL.
1025+
1026+
:typoscript:`plugin.tx_dlf_modeldownloadtool.`
1027+
1028+
Viewer selection tool
1029+
^^^^^^^^^^^^^
1030+
1031+
This tool can display a selection list of configured 3D viewers (from the "dlf_3d_viewers" directory see :ref:`Embedded 3D Viewer Setup`) that support the current model.
1032+
1033+
The model URL is extracted from the METS file or taken from the provided model parameter. The extension of the model is extracted from this URL and compared with the supported model formats specified in the respective viewer configuration.
1034+
1035+
:typoscript:`plugin.tx_dlf_viewerselectiontool.`
10211036

10221037
Search in Document Tool
10231038
^^^^^^^^^^^^^^^^^^^^^^^

Resources/Private/Language/de.locallang.xlf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,10 @@
477477
<source><![CDATA[Search in document]]></source>
478478
<target><![CDATA[Im Dokument suchen]]></target>
479479
</trans-unit>
480+
<trans-unit id="tools.viewerselection.default" approved="yes">
481+
<source><![CDATA[Default]]></source>
482+
<target><![CDATA[Standard]]></target>
483+
</trans-unit>
480484
<trans-unit id="volume" approved="yes">
481485
<source><![CDATA[volume]]></source>
482486
<target><![CDATA[Band]]></target>

Resources/Private/Language/de.locallang_labels.xlf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,10 @@
701701
<target>Audio Datei Nutzungsgruppen: Komma-getrennte Liste der @USE Attributwerte der Audiodateien nach absteigender Priorität sortiert (Standard ist "AUDIO")</target>
702702
<source>Audio file use groups: comma-separated list of @USE attribute values ordered by decreasing priority (default is "AUDIO")</source>
703703
</trans-unit>
704+
<trans-unit id="config.files.useGroupsModel">
705+
<target>Modell Datei Nutzungsgruppen: Komma-getrennte Liste der @USE Attributwerte der Modelldateien nach absteigender Priorität sortiert (Standard ist "DEFAULT")</target>
706+
<source>Model file use groups: comma-separated list of @USE attribute values ordered by decreasing priority (default is "DEFAULT")</source>
707+
</trans-unit>
704708
<trans-unit id="config.iiif.indexAnnotations">
705709
<target>IIIF-Annotationen mit Motivation "painting" als Volltext behandeln?: Als Volltext behandelte Annotationen werden im Suchid idiert (Standard ist "FALSE")</target>
706710
<source>Handle IIIF annotations with motivation "painting" as fulltext?: Handling annotations as fulltexts means they are ided (default is "FALSE")</source>

Resources/Private/Language/locallang.xlf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@
269269
<trans-unit id="tools.searchindocument.loading">
270270
<source><![CDATA[Loading...]]></source>
271271
</trans-unit>
272+
<trans-unit id="tools.viewerselection.default">
273+
<source><![CDATA[Default]]></source>
274+
</trans-unit>
272275
<trans-unit id="search.logicalPage">
273276
<source><![CDATA[Page]]></source>
274277
</trans-unit>

Resources/Private/Language/locallang_labels.xlf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,9 @@
527527
<trans-unit id="config.files.useGroupsAudio">
528528
<source>Audio file use groups: comma-separated list of @USE attribute values ordered by decreasing priority (default is "AUDIO")</source>
529529
</trans-unit>
530+
<trans-unit id="config.files.useGroupsModel">
531+
<source>Model file use groups: comma-separated list of @USE attribute values ordered by decreasing priority (default is "DEFAULT")</source>
532+
</trans-unit>
530533
<trans-unit id="config.iiif.indexAnnotations">
531534
<source>Handle IIIF annotations with motivation "painting" as fulltext?: Handling annotations as fulltexts means they are ided (default is "FALSE")</source>
532535
</trans-unit>

Resources/Private/Templates/Toolbox/Main.html

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,39 @@
7575
</f:then>
7676
</f:if>
7777

78-
<f:if condition="{renderModelDownloadTool} && {modelDownload}">
78+
<f:if condition="{renderModelDownloadTool} && {modelUrl}">
7979
<f:then>
8080
<li>
81-
<span class="tx-dlf-tools-modeldownload">
82-
<f:link.external uri="{modelDownload.url}">
83-
<f:translate key="downloadModel" />
84-
</f:link.external>
85-
</span>
81+
<span class="tx-dlf-tools-modeldownload">
82+
<f:link.external uri="{modelUrl}">
83+
<f:translate key="downloadModel"/>
84+
</f:link.external>
85+
</span>
8686
</li>
8787
</f:then>
8888
</f:if>
8989

90+
<f:if condition="{renderViewerSelectionTool} && {viewers}">
91+
<f:then>
92+
<form method="get" action="{f:uri.page(pageUid='{viewData.requestData.pageUid}')}">
93+
<f:if condition="{viewData.requestData.id}">
94+
<f:form.hidden name="tx_dlf[id]" value="{viewData.requestData.id}"/>
95+
</f:if>
96+
<f:if condition="{viewData.requestData.model}">
97+
<f:form.hidden name="tx_dlf[model]" value="{viewData.requestData.model}"/>
98+
</f:if>
99+
<f:form.select id="tx-dlf-viewer-{viewData.uniqueId}" name="tx_dlf[viewer]"
100+
options="{viewers}"
101+
optionValueField="id"
102+
optionLabelField="name"
103+
value="{viewData.requestData.viewer}"
104+
additionalAttributes="{'onchange': 'javascript:this.form.submit();'}"
105+
prependOptionLabel="{f:translate(key: 'tools.viewerselection.default', extensionName: 'dlf')}">
106+
</f:form.select>
107+
<form>
108+
</f:then>
109+
</f:if>
110+
90111
<f:if condition="{renderFulltextTool}">
91112
<f:then>
92113
<li>

ext_conf_template.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ files.useGroupsDownload = DOWNLOAD
3030
files.useGroupsFulltext = FULLTEXT
3131
# cat=Files; type=string; label=LLL:EXT:dlf/Resources/Private/Language/locallang_labels.xlf:config.files.useGroupsScore
3232
files.useGroupsScore = SCORE
33+
# cat=Files; type=string; label=LLL:EXT:dlf/Resources/Private/Language/locallang_labels.xlf:config.files.useGroupsModel
34+
files.useGroupsModel = DEFAULT
3335
# cat=IIIF; type=boolean; label=LLL:EXT:dlf/Resources/Private/Language/locallang_labels.xlf:config.iiif.indexAnnotations
3436
iiif.indexAnnotations = 0
3537
# cat=IIIF; type=int[1-2000]; label=LLL:EXT:dlf/Resources/Private/Language/locallang_labels.xlf:config.iiif.thumbnailWidth

0 commit comments

Comments
 (0)