Warning, /graphics/peruse/src/app/qml/viewers/okular.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) version 3, or any
0008  * later version accepted by the membership of KDE e.V. (or its
0009  * successor approved by the membership of KDE e.V.), which shall
0010  * act as a proxy defined in Section 6 of version 3 of the license.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0019  *
0020  */
0021 
0022 import QtQuick 2.12
0023 import QtQuick.Controls 2.12 as QtControls
0024 
0025 import org.kde.kirigami 2.7 as Kirigami
0026 import org.kde.okular 2.0 as Okular
0027 
0028 import "helpers" as Helpers
0029 
0030 /**
0031  * @brief a ViewerBase intended as a fallback for unsupported books.
0032  * 
0033  * It is called from Book when the opened book has no other specialised viewers.
0034  * 
0035  * It does not use the ImageBrowser because it needs to access
0036  * Okular Page items for the images.
0037  */
0038 ViewerBase {
0039     id: root;
0040     title: documentItem.windowTitleForDocument;
0041     onFileChanged: documentItem.url = "file://" + file;
0042     onCurrentPageChanged: {
0043         if(documentItem.currentPage !== currentPage) {
0044             documentItem.currentPage = currentPage;
0045         }
0046         if(currentPage !== imageBrowser.currentIndex) {
0047             pageChangeAnimation.running = false;
0048             var currentPos = imageBrowser.contentX;
0049             var newPos;
0050             imageBrowser.positionViewAtIndex(currentPage, ListView.Center);
0051             imageBrowser.currentIndex = currentPage;
0052             newPos = imageBrowser.contentX;
0053             pageChangeAnimation.from = currentPos;
0054             pageChangeAnimation.to = newPos;
0055             pageChangeAnimation.running = true;
0056         }
0057     }
0058     NumberAnimation { id: pageChangeAnimation; target: imageBrowser; property: "contentX"; duration: applicationWindow().animationDuration; easing.type: Easing.InOutQuad; }
0059     onRtlModeChanged: {
0060         if(rtlMode === true) {
0061             imageBrowser.layoutDirection = Qt.RightToLeft;
0062         }
0063         else {
0064             imageBrowser.layoutDirection = Qt.LeftToRight;
0065         }
0066         root.restoreCurrentPage();
0067     }
0068     onRestoreCurrentPage: {
0069         // This is un-pretty, quite obviously. But thanks to the ListView's inability to
0070         // stay in place when the geometry changes, well, this makes things simple.
0071         imageBrowser.positionViewAtIndex(imageBrowser.currentIndex, ListView.Center);
0072 
0073     }
0074     pageCount: documentItem.pageCount;
0075     thumbnailComponent: thumbnailComponent;
0076     pagesModel: documentItem.matchingPages;
0077     Component {
0078         id: thumbnailComponent;
0079         Item {
0080             width: parent.width;
0081             height: Kirigami.Units.gridUnit * 6;
0082             MouseArea {
0083                 anchors.fill: parent;
0084                 onClicked: viewLoader.item.currentPage = model.index;
0085             }
0086             Rectangle {
0087                 anchors.fill: parent;
0088                 color: Kirigami.Theme.highlightColor;
0089                 opacity: root.currentPage === model.index ? 1 : 0;
0090                 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration; } }
0091             }
0092             Okular.ThumbnailItem {
0093                 id: thumbnail
0094                 anchors {
0095                     top: parent.top;
0096                     horizontalCenter: parent.horizontalCenter;
0097                     margins: Kirigami.Units.smallSpacing;
0098                 }
0099                 document: documentItem
0100                 pageNumber: modelData
0101                 height: parent.height - pageTitle.height - Kirigami.Units.smallSpacing * 2;
0102                 function updateWidth() {
0103                     width = Math.round(height * (implicitWidth / implicitHeight));
0104                 }
0105                 Component.onCompleted: updateWidth();
0106                 onHeightChanged: updateWidth();
0107                 onImplicitHeightChanged: updateWidth();
0108             }
0109             QtControls.Label {
0110                 id: pageTitle;
0111                 anchors {
0112                     left: parent.left;
0113                     right: parent.right;
0114                     bottom: parent.bottom;
0115                 }
0116                 height: paintedHeight;
0117                 text: modelData + 1;
0118                 elide: Text.ElideMiddle;
0119                 horizontalAlignment: Text.AlignHCenter;
0120             }
0121         }
0122     }
0123     Okular.DocumentItem {
0124         id: documentItem
0125         onOpenedChanged: {
0126             if(opened === true) {
0127                 root.loadingCompleted(true);
0128                 initialPageChange.start();
0129             } else {
0130                 console.debug("Well then, error loading the file...");
0131             }
0132         }
0133         onCurrentPageChanged: {
0134             if(root.currentPage !== currentPage) {
0135                 root.currentPage = currentPage;
0136             }
0137         }
0138     }
0139 
0140     Timer {
0141         id: initialPageChange;
0142         interval: applicationWindow().animationDuration;
0143         running: false;
0144         repeat: false;
0145         onTriggered: root.currentPage = imageBrowser.currentIndex;
0146     }
0147     ListView {
0148         id: imageBrowser
0149         anchors.fill: parent;
0150         model: documentItem.matchingPages;
0151 
0152         interactive: false // No interactive flicky stuff here, we'll handle that with the navigator instance
0153         property int imageWidth: root.width + Kirigami.Units.largeSpacing;
0154         property int imageHeight: root.height;
0155 
0156         orientation: ListView.Horizontal
0157         snapMode: ListView.SnapOneItem
0158 
0159         // This ensures that the current index is always up to date, which we need to ensure we can track the current page
0160         // as required by the thumbnail navigator, and the resume-reading-from functionality
0161         onMovementEnded: {
0162             var indexHere = indexAt(contentX + width / 2, contentY + height / 2);
0163             if(currentIndex !== indexHere) {
0164                 currentIndex = indexHere;
0165             }
0166         }
0167 
0168         delegate: Flickable {
0169             id: flick
0170             width: imageBrowser.imageWidth
0171             height: imageBrowser.imageHeight
0172             contentWidth: imageBrowser.imageWidth
0173             contentHeight: imageBrowser.imageHeight
0174             interactive: contentWidth > width || contentHeight > height
0175             z: interactive ? 1000 : 0
0176             PinchArea {
0177                 width: Math.max(flick.contentWidth, flick.width)
0178                 height: Math.max(flick.contentHeight, flick.height)
0179 
0180                 property real initialWidth
0181                 property real initialHeight
0182 
0183                 onPinchStarted: {
0184                     initialWidth = flick.contentWidth
0185                     initialHeight = flick.contentHeight
0186                 }
0187 
0188                 onPinchUpdated: {
0189                     // adjust content pos due to drag
0190                     flick.contentX += pinch.previousCenter.x - pinch.center.x
0191                     flick.contentY += pinch.previousCenter.y - pinch.center.y
0192 
0193                     // resize content
0194                     flick.resizeContent(Math.max(imageBrowser.imageWidth, initialWidth * pinch.scale), Math.max(imageBrowser.imageHeight, initialHeight * pinch.scale), pinch.center)
0195                 }
0196 
0197                 onPinchFinished: {
0198                     // Move its content within bounds.
0199                     flick.returnToBounds();
0200                 }
0201 
0202                 Item {
0203                     implicitWidth: page.implicitWidth
0204                     implicitHeight: page.implicitHeight
0205                     width: flick.contentWidth
0206                     height: flick.contentHeight
0207                     Okular.PageItem {
0208                         id: page;
0209                         document: documentItem;
0210                         pageNumber: index;
0211                         anchors.centerIn: parent;
0212                         property real pageRatio: implicitWidth / implicitHeight
0213                         property bool sameOrientation: root.width / root.height > pageRatio
0214                         width: sameOrientation ? parent.height * pageRatio : parent.width
0215                         height: !sameOrientation ? parent.width / pageRatio : parent.height
0216                     }
0217                     MouseArea {
0218                         anchors.fill: parent;
0219                         enabled: flick.interactive
0220                         onClicked: startToggleControls()
0221                         onDoubleClicked: {
0222                             abortToggleControls();
0223                             flick.resizeContent(imageBrowser.imageWidth, imageBrowser.imageHeight, Qt.point(imageBrowser.imageWidth/2, imageBrowser.imageHeight/2));
0224                             flick.returnToBounds();
0225                         }
0226                     }
0227                 }
0228             }
0229         }
0230     }
0231 
0232     Helpers.Navigator {
0233         enabled: !imageBrowser.currentItem.interactive;
0234         anchors.fill: parent;
0235         onLeftRequested: imageBrowser.layoutDirection == Qt.RightToLeft? root.goNextPage(): root.goPreviousPage();
0236         onRightRequested: imageBrowser.layoutDirection == Qt.RightToLeft? root.goPreviousPage(): root.goNextPage();
0237         onTapped: startToggleControls();
0238         onDoubleTapped: {
0239             abortToggleControls();
0240             imageBrowser.currentItem.resizeContent(imageBrowser.imageWidth * 2, imageBrowser.imageHeight * 2, Qt.point(eventPoint.x, eventPoint.y));
0241             imageBrowser.currentItem.returnToBounds();
0242         }
0243     }
0244 }