Implemented history (position stack)
Allows the user to return back after selecting a cross-page link
This commit is contained in:
parent
59f49be0c3
commit
9ac726c523
17 changed files with 1183 additions and 329 deletions
|
@ -109,6 +109,7 @@ SOURCES += \
|
||||||
src/BooksImportModel.cpp \
|
src/BooksImportModel.cpp \
|
||||||
src/BooksListWatcher.cpp \
|
src/BooksListWatcher.cpp \
|
||||||
src/BooksLoadingProperty.cpp \
|
src/BooksLoadingProperty.cpp \
|
||||||
|
src/BooksPageStack.cpp \
|
||||||
src/BooksPageWidget.cpp \
|
src/BooksPageWidget.cpp \
|
||||||
src/BooksPaintContext.cpp \
|
src/BooksPaintContext.cpp \
|
||||||
src/BooksPathModel.cpp \
|
src/BooksPathModel.cpp \
|
||||||
|
@ -150,6 +151,7 @@ HEADERS += \
|
||||||
src/BooksItem.h \
|
src/BooksItem.h \
|
||||||
src/BooksListWatcher.h \
|
src/BooksListWatcher.h \
|
||||||
src/BooksLoadingProperty.h \
|
src/BooksLoadingProperty.h \
|
||||||
|
src/BooksPageStack.h \
|
||||||
src/BooksPageWidget.h \
|
src/BooksPageWidget.h \
|
||||||
src/BooksPaintContext.h \
|
src/BooksPaintContext.h \
|
||||||
src/BooksPathModel.h \
|
src/BooksPathModel.h \
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2015-2016 Jolla Ltd.
|
Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
Contact: Slava Monich <slava.monich@jolla.com>
|
Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
|
|
||||||
You may use this file under the terms of BSD license as follows:
|
You may use this file under the terms of BSD license as follows:
|
||||||
|
@ -43,8 +43,8 @@ SilicaFlickable {
|
||||||
signal pageClicked(var page)
|
signal pageClicked(var page)
|
||||||
|
|
||||||
property int orientation: Orientation.Portrait
|
property int orientation: Orientation.Portrait
|
||||||
property int _currentPage: bookListWatcher.currentIndex
|
property alias stackModel: bookModel.pageStack
|
||||||
property bool _loading: minLoadingDelay.running || bookModel.loading
|
property bool loading: bookModel.loading
|
||||||
property var _currentState: _visibilityStates[Settings.pageDetails % _visibilityStates.length]
|
property var _currentState: _visibilityStates[Settings.pageDetails % _visibilityStates.length]
|
||||||
readonly property var _visibilityStates: [
|
readonly property var _visibilityStates: [
|
||||||
{ pager: false, page: false, title: false, tools: false },
|
{ pager: false, page: false, title: false, tools: false },
|
||||||
|
@ -52,18 +52,6 @@ SilicaFlickable {
|
||||||
{ pager: true, page: true, title: true, tools: true }
|
{ pager: true, page: true, title: true, tools: true }
|
||||||
]
|
]
|
||||||
|
|
||||||
// NOTE: These have to match ResetReason in BooksBookModel
|
|
||||||
readonly property var _loadingTextLabel: [
|
|
||||||
//% "Formatting..."
|
|
||||||
qsTrId("harbour-books-book-view-formatting"),
|
|
||||||
//% "Loading..."
|
|
||||||
qsTrId("harbour-books-book-view-loading"),
|
|
||||||
//% "Applying larger fonts..."
|
|
||||||
qsTrId("harbour-books-book-view-applying_larger_fonts"),
|
|
||||||
//% "Applying smaller fonts..."
|
|
||||||
qsTrId("harbour-books-book-view-applying_smaller_fonts")
|
|
||||||
]
|
|
||||||
|
|
||||||
interactive: (!linkMenu || !linkMenu.visible) &&
|
interactive: (!linkMenu || !linkMenu.visible) &&
|
||||||
(!imageView || !imageView.visible) &&
|
(!imageView || !imageView.visible) &&
|
||||||
(!footnoteView || !footnoteView.visible)
|
(!footnoteView || !footnoteView.visible)
|
||||||
|
@ -101,49 +89,14 @@ SilicaFlickable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: minLoadingDelay
|
|
||||||
interval: 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: resetPager
|
|
||||||
interval: 0
|
|
||||||
onTriggered: {
|
|
||||||
if (_currentPage >= 0) {
|
|
||||||
console.log("resetting pager to", _currentPage)
|
|
||||||
pager.currentPage = _currentPage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BookModel {
|
BookModel {
|
||||||
id: bookModel
|
id: bookModel
|
||||||
book: root.book ? root.book : null
|
book: root.book ? root.book : null
|
||||||
size: bookListWatcher.size
|
size: bookViewWatcher.size
|
||||||
currentPage: _currentPage
|
|
||||||
leftMargin: Theme.horizontalPageMargin
|
leftMargin: Theme.horizontalPageMargin
|
||||||
rightMargin: Theme.horizontalPageMargin
|
rightMargin: Theme.horizontalPageMargin
|
||||||
topMargin: Theme.itemSizeSmall
|
topMargin: Theme.itemSizeSmall
|
||||||
bottomMargin: Theme.itemSizeSmall
|
bottomMargin: Theme.itemSizeSmall
|
||||||
onJumpToPage: bookView.jumpTo(index)
|
|
||||||
onCurrentPageChanged: {
|
|
||||||
if (linkMenu) linkMenu.hide()
|
|
||||||
if (currentPage >= 0 && bookView._jumpingTo < 0) {
|
|
||||||
pager.currentPage = currentPage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onLoadingChanged: {
|
|
||||||
if (loading && !pageCount) {
|
|
||||||
minLoadingDelay.start()
|
|
||||||
bookView._jumpingTo = -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ListWatcher {
|
|
||||||
id: bookListWatcher
|
|
||||||
listView: bookView
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SilicaListView {
|
SilicaListView {
|
||||||
|
@ -154,9 +107,50 @@ SilicaFlickable {
|
||||||
orientation: ListView.Horizontal
|
orientation: ListView.Horizontal
|
||||||
snapMode: ListView.SnapOneItem
|
snapMode: ListView.SnapOneItem
|
||||||
spacing: Theme.paddingMedium
|
spacing: Theme.paddingMedium
|
||||||
opacity: _loading ? 0 : 1
|
opacity: loading ? 0 : 1
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
interactive: root.interactive
|
interactive: root.interactive
|
||||||
|
readonly property int currentPage: stackModel.currentPage
|
||||||
|
property bool completed
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
//console.log(currentPage)
|
||||||
|
bookViewWatcher.positionViewAtIndex(currentPage)
|
||||||
|
completed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentPageChanged: {
|
||||||
|
//console.log(currentPage, completed, flicking)
|
||||||
|
if (completed && !flicking) {
|
||||||
|
bookViewWatcher.positionViewAtIndex(currentPage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFlickingChanged: {
|
||||||
|
if (!flicking) {
|
||||||
|
bookViewWatcher.updateModel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListWatcher {
|
||||||
|
id: bookViewWatcher
|
||||||
|
listView: bookView
|
||||||
|
onCurrentIndexChanged: {
|
||||||
|
if (listView.completed && !listView.flicking && currentIndex >= 0) {
|
||||||
|
//console.log(currentIndex, listView.completed, listView.flicking)
|
||||||
|
updateModel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function updateModel() {
|
||||||
|
if (linkMenu) linkMenu.hide()
|
||||||
|
//console.trace()
|
||||||
|
stackModel.currentPage = currentIndex
|
||||||
|
if (!pager.pressed) {
|
||||||
|
pager.currentPage = currentIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delegate: BooksPageView {
|
delegate: BooksPageView {
|
||||||
width: bookView.width
|
width: bookView.width
|
||||||
height: bookView.height
|
height: bookView.height
|
||||||
|
@ -172,12 +166,13 @@ SilicaFlickable {
|
||||||
pageNumberVisible: _currentState.page
|
pageNumberVisible: _currentState.page
|
||||||
title: bookModel.title
|
title: bookModel.title
|
||||||
onJumpToPage: bookView.jumpTo(page)
|
onJumpToPage: bookView.jumpTo(page)
|
||||||
|
onPushPosition: stackModel.pushPosition(position) // bookView.jumpTo(page)
|
||||||
onPageClicked: {
|
onPageClicked: {
|
||||||
root.pageClicked(index)
|
root.pageClicked(index)
|
||||||
Settings.pageDetails = (Settings.pageDetails+ 1) % _visibilityStates.length
|
Settings.pageDetails = (Settings.pageDetails + 1) % _visibilityStates.length
|
||||||
}
|
}
|
||||||
onImagePressed: {
|
onImagePressed: {
|
||||||
if (_currentPage == index) {
|
if (bookViewWatcher.currentIndex == index) {
|
||||||
if (!imageView) {
|
if (!imageView) {
|
||||||
imageView = imageViewComponent.createObject(root)
|
imageView = imageViewComponent.createObject(root)
|
||||||
}
|
}
|
||||||
|
@ -185,7 +180,7 @@ SilicaFlickable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onBrowserLinkPressed: {
|
onBrowserLinkPressed: {
|
||||||
if (_currentPage == index) {
|
if (bookViewWatcher.currentIndex == index) {
|
||||||
if (!linkMenu) {
|
if (!linkMenu) {
|
||||||
linkMenu = linkMenuComponent.createObject(root)
|
linkMenu = linkMenuComponent.createObject(root)
|
||||||
}
|
}
|
||||||
|
@ -193,7 +188,7 @@ SilicaFlickable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onFootnotePressed: {
|
onFootnotePressed: {
|
||||||
if (_currentPage == index) {
|
if (bookViewWatcher.currentIndex == index) {
|
||||||
if (!footnoteView) {
|
if (!footnoteView) {
|
||||||
footnoteView = footnoteViewComponent.createObject(root)
|
footnoteView = footnoteViewComponent.createObject(root)
|
||||||
}
|
}
|
||||||
|
@ -202,15 +197,15 @@ SilicaFlickable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property int _jumpingTo: -1
|
property int jumpingTo: -1
|
||||||
function jumpTo(page) {
|
function jumpTo(page) {
|
||||||
if (page >=0 && page !== _currentPage) {
|
if (page >=0 && page !== bookViewWatcher.currentIndex) {
|
||||||
_jumpingTo = page
|
jumpingTo = page
|
||||||
positionViewAtIndex(page, ListView.Center)
|
bookViewWatcher.positionViewAtIndex(page)
|
||||||
pager.currentPage = page
|
pager.currentPage = page
|
||||||
_jumpingTo = -1
|
jumpingTo = -1
|
||||||
if (_currentPage !== page) {
|
if (bookViewWatcher.currentIndex !== page) {
|
||||||
console.log("oops, still at", _currentPage)
|
console.log("oops, still at", currentPage)
|
||||||
resetPager.restart()
|
resetPager.restart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +213,15 @@ SilicaFlickable {
|
||||||
|
|
||||||
Behavior on opacity { FadeAnimation {} }
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: resetPager
|
||||||
|
interval: 0
|
||||||
|
onTriggered: {
|
||||||
|
console.log("resetting pager to", bookViewWatcher.currentIndex)
|
||||||
|
pager.currentPage = bookViewWatcher.currentIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BooksPageTools {
|
BooksPageTools {
|
||||||
id: pageTools
|
id: pageTools
|
||||||
anchors {
|
anchors {
|
||||||
|
@ -228,7 +232,7 @@ SilicaFlickable {
|
||||||
leftMargin: bookModel.leftMargin
|
leftMargin: bookModel.leftMargin
|
||||||
rightMargin: bookModel.rightMargin
|
rightMargin: bookModel.rightMargin
|
||||||
opacity: _currentState.tools ? 1 : 0
|
opacity: _currentState.tools ? 1 : 0
|
||||||
visible: opacity > 0 && book && bookModel.pageCount && !_loading
|
visible: opacity > 0 && book && bookModel.pageCount && !loading
|
||||||
Behavior on opacity { FadeAnimation {} }
|
Behavior on opacity { FadeAnimation {} }
|
||||||
onIncreaseFontSize: bookModel.increaseFontSize()
|
onIncreaseFontSize: bookModel.increaseFontSize()
|
||||||
onDecreaseFontSize: bookModel.decreaseFontSize()
|
onDecreaseFontSize: bookModel.decreaseFontSize()
|
||||||
|
@ -237,9 +241,14 @@ SilicaFlickable {
|
||||||
BooksPager {
|
BooksPager {
|
||||||
id: pager
|
id: pager
|
||||||
anchors {
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
bottomMargin: (Theme.itemSizeExtraSmall + 2*(bookModel.bottomMargin - height))/4
|
bottomMargin: (Theme.itemSizeExtraSmall + 2*(bookModel.bottomMargin - height))/4
|
||||||
}
|
}
|
||||||
|
leftMargin: bookModel.leftMargin
|
||||||
|
rightMargin: bookModel.rightMargin
|
||||||
|
stack: stackModel
|
||||||
pageCount: bookModel.pageCount
|
pageCount: bookModel.pageCount
|
||||||
width: parent.width
|
width: parent.width
|
||||||
opacity: (_currentState.pager && book && bookModel.pageCount) ? 0.75 : 0
|
opacity: (_currentState.pager && book && bookModel.pageCount) ? 0.75 : 0
|
||||||
|
@ -261,20 +270,20 @@ SilicaFlickable {
|
||||||
text: bookModel.title
|
text: bookModel.title
|
||||||
height: Theme.itemSizeExtraSmall
|
height: Theme.itemSizeExtraSmall
|
||||||
color: Theme.highlightColor
|
color: Theme.highlightColor
|
||||||
opacity: _loading ? 0.6 : 0
|
opacity: loading ? 0.6 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
BusyIndicator {
|
BusyIndicator {
|
||||||
id: busyIndicator
|
id: busyIndicator
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
size: BusyIndicatorSize.Large
|
size: BusyIndicatorSize.Large
|
||||||
running: _loading
|
running: loading
|
||||||
}
|
}
|
||||||
|
|
||||||
BooksFitLabel {
|
BooksFitLabel {
|
||||||
anchors.fill: busyIndicator
|
anchors.fill: busyIndicator
|
||||||
text: bookModel.progress > 0 ? bookModel.progress : ""
|
text: bookModel.progress > 0 ? bookModel.progress : ""
|
||||||
opacity: (_loading && bookModel.progress > 0) ? 1 : 0
|
opacity: (loading && bookModel.progress > 0) ? 1 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
@ -286,7 +295,7 @@ SilicaFlickable {
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
onClicked: root.closeBook()
|
onClicked: root.closeBook()
|
||||||
enabled: _loading && bookModel.resetReason === BookModel.ReasonLoading
|
enabled: loading && bookModel.resetReason === BookModel.ReasonLoading
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
opacity: enabled ? 1.0 : 0.0
|
opacity: enabled ? 1.0 : 0.0
|
||||||
Behavior on opacity { FadeAnimation { } }
|
Behavior on opacity { FadeAnimation { } }
|
||||||
|
@ -301,9 +310,19 @@ SilicaFlickable {
|
||||||
}
|
}
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
color: Theme.highlightColor
|
color: Theme.highlightColor
|
||||||
opacity: _loading ? 1 : 0
|
opacity: loading ? 1 : 0
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
Behavior on opacity { FadeAnimation {} }
|
Behavior on opacity { FadeAnimation {} }
|
||||||
text: bookModel ? _loadingTextLabel[bookModel.resetReason] : ""
|
text: bookModel ? (bookModel.resetReason == BookModel.ReasonLoading ?
|
||||||
|
//% "Loading..."
|
||||||
|
qsTrId("harbour-books-book-view-loading") :
|
||||||
|
bookModel.resetReason == BookModel.ReasonIncreasingFontSize ?
|
||||||
|
//% "Applying larger fonts..."
|
||||||
|
qsTrId("harbour-books-book-view-applying_larger_fonts") :
|
||||||
|
bookModel.resetReason == BookModel.ReasonDecreasingFontSize ?
|
||||||
|
//% "Applying smaller fonts..."
|
||||||
|
qsTrId("harbour-books-book-view-applying_smaller_fonts") :
|
||||||
|
//% "Formatting..."
|
||||||
|
qsTrId("harbour-books-book-view-formatting")) : ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2015-2016 Jolla Ltd.
|
Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
Contact: Slava Monich <slava.monich@jolla.com>
|
Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
|
|
||||||
You may use this file under the terms of BSD license as follows:
|
You may use this file under the terms of BSD license as follows:
|
||||||
|
@ -54,6 +54,7 @@ Item {
|
||||||
signal footnotePressed(var touchX, var touchY, var text, var url)
|
signal footnotePressed(var touchX, var touchY, var text, var url)
|
||||||
signal browserLinkPressed(var url)
|
signal browserLinkPressed(var url)
|
||||||
signal jumpToPage(var page)
|
signal jumpToPage(var page)
|
||||||
|
signal pushPosition(var position)
|
||||||
|
|
||||||
PageWidget {
|
PageWidget {
|
||||||
id: widget
|
id: widget
|
||||||
|
@ -63,6 +64,7 @@ Item {
|
||||||
onImagePressed: view.imagePressed(imageId, rect)
|
onImagePressed: view.imagePressed(imageId, rect)
|
||||||
onActiveTouch: pressImage.animate(touchX, touchY)
|
onActiveTouch: pressImage.animate(touchX, touchY)
|
||||||
onJumpToPage: view.jumpToPage(page)
|
onJumpToPage: view.jumpToPage(page)
|
||||||
|
onPushPosition: view.pushPosition(position)
|
||||||
onShowFootnote: view.footnotePressed(touchX,touchY,text,imageId)
|
onShowFootnote: view.footnotePressed(touchX,touchY,text,imageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2015-2016 Jolla Ltd.
|
Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
Contact: Slava Monich <slava.monich@jolla.com>
|
Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
|
|
||||||
You may use this file under the terms of BSD license as follows:
|
You may use this file under the terms of BSD license as follows:
|
||||||
|
@ -38,29 +38,82 @@ Item {
|
||||||
id: root
|
id: root
|
||||||
height: slider.height
|
height: slider.height
|
||||||
|
|
||||||
property alias pageCount: slider.maximumValue
|
property var stack
|
||||||
|
property int pageCount
|
||||||
|
property real leftMargin: Theme.horizontalPageMargin
|
||||||
|
property real rightMargin: Theme.horizontalPageMargin
|
||||||
property alias currentPage: slider.value
|
property alias currentPage: slider.value
|
||||||
property alias pressed: slider.pressed
|
property alias pressed: slider.pressed
|
||||||
property alias leftMargin: slider.leftMargin
|
|
||||||
property alias rightMargin: slider.rightMargin
|
|
||||||
|
|
||||||
signal pageChanged(var page)
|
signal pageChanged(var page)
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: navigateBackArea
|
||||||
|
property bool down: pressed && containsMouse
|
||||||
|
width: navigateBack.width + root.leftMargin
|
||||||
|
height: navigateBack.height
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
onClicked: stack.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
id: navigateBack
|
||||||
|
icon.source: "image://theme/icon-m-left?" + Settings.primaryPageToolColor
|
||||||
|
down: navigateBackArea.down || (pressed && containsMouse)
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: root.leftMargin
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
onClicked: stack.back()
|
||||||
|
}
|
||||||
|
|
||||||
BooksPageSlider {
|
BooksPageSlider {
|
||||||
id: slider
|
id: slider
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: navigateBack.right
|
||||||
right: parent.right
|
right: navigateForwardArea.left
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
}
|
}
|
||||||
stepSize: 1
|
stepSize: 1
|
||||||
minimumValue: 0
|
minimumValue: 0
|
||||||
|
maximumValue: pageCount > 0 ? pageCount - 1 : 0
|
||||||
valueText: ""
|
valueText: ""
|
||||||
label: ""
|
label: ""
|
||||||
|
leftMargin: Theme.horizontalPageMargin
|
||||||
|
rightMargin: Theme.horizontalPageMargin
|
||||||
primaryColor: Settings.primaryPageToolColor
|
primaryColor: Settings.primaryPageToolColor
|
||||||
secondaryColor: Settings.primaryPageToolColor
|
secondaryColor: Settings.primaryPageToolColor
|
||||||
highlightColor: Settings.highlightPageToolColor
|
highlightColor: Settings.highlightPageToolColor
|
||||||
secondaryHighlightColor: Settings.highlightPageToolColor
|
secondaryHighlightColor: Settings.highlightPageToolColor
|
||||||
onSliderValueChanged: root.pageChanged(value)
|
onSliderValueChanged: root.pageChanged(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: navigateForwardArea
|
||||||
|
property bool down: pressed && containsMouse
|
||||||
|
width: navigateForward.width + root.rightMargin
|
||||||
|
height: navigateForward.height
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
onClicked: stack.forward()
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
id: navigateForward
|
||||||
|
icon.source: "image://theme/icon-m-right?" + Settings.primaryPageToolColor
|
||||||
|
down: navigateForwardArea.down || (pressed && containsMouse)
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: root.rightMargin
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
onClicked: stack.forward()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
* notice, this list of conditions and the following disclaimer in
|
* notice, this list of conditions and the following disclaimer in
|
||||||
* the documentation and/or other materials provided with the
|
* the documentation and/or other materials provided with the
|
||||||
* distribution.
|
* distribution.
|
||||||
* * Neither the name of Nemo Mobile nor the names of its contributors
|
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||||
* may be used to endorse or promote products derived from this
|
* may be used to endorse or promote products derived from this
|
||||||
* software without specific prior written permission.
|
* software without specific prior written permission.
|
||||||
*
|
*
|
||||||
|
@ -58,6 +58,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define BOOK_STATE_PAGE_STACK_INDEX "pageStackIndex"
|
||||||
#define BOOK_STATE_FONT_SIZE_ADJUST "fontSizeAdjust"
|
#define BOOK_STATE_FONT_SIZE_ADJUST "fontSizeAdjust"
|
||||||
#define BOOK_STATE_POSITION "position"
|
#define BOOK_STATE_POSITION "position"
|
||||||
#define BOOK_COVER_SUFFIX ".cover."
|
#define BOOK_COVER_SUFFIX ".cover."
|
||||||
|
@ -328,10 +329,40 @@ BooksBook::BooksBook(const BooksStorage& aStorage, QString aRelativePath,
|
||||||
// Load the state
|
// Load the state
|
||||||
QVariantMap state;
|
QVariantMap state;
|
||||||
if (HarbourJson::load(iStateFilePath, state)) {
|
if (HarbourJson::load(iStateFilePath, state)) {
|
||||||
iLastPos = BooksPos::fromVariant(state.value(BOOK_STATE_POSITION));
|
|
||||||
iFontSizeAdjust = state.value(BOOK_STATE_FONT_SIZE_ADJUST).toInt();
|
iFontSizeAdjust = state.value(BOOK_STATE_FONT_SIZE_ADJUST).toInt();
|
||||||
|
#ifdef BOOK_STATE_PAGE_STACK_INDEX
|
||||||
|
iPageStackPos = state.value(BOOK_STATE_PAGE_STACK_INDEX).toInt();
|
||||||
|
#endif
|
||||||
|
// Current position can be stored in two formats - a single
|
||||||
|
// position (older format) or a list of position (newer one).
|
||||||
|
// We have to detect which one we are dealing with
|
||||||
|
QVariant position(state.value(BOOK_STATE_POSITION));
|
||||||
|
BooksPos bookPos(BooksPos::fromVariant(position));
|
||||||
|
if (bookPos.valid()) {
|
||||||
|
// Old format (single position)
|
||||||
|
iPageStack.append(bookPos);
|
||||||
|
} else {
|
||||||
|
// New format (list of positions)
|
||||||
|
QVariantList list(position.toList());
|
||||||
|
const int count = list.count();
|
||||||
|
for (int k=0; k<count; k++) {
|
||||||
|
bookPos = BooksPos::fromVariant(list.at(k));
|
||||||
|
if (bookPos.valid()) {
|
||||||
|
iPageStack.append(bookPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Validate the state
|
||||||
|
if (iPageStack.isEmpty()) {
|
||||||
|
iPageStack.append(BooksPos(0,0,0));
|
||||||
|
}
|
||||||
|
if (iPageStackPos < 0) {
|
||||||
|
iPageStackPos = 0;
|
||||||
|
} else if (iPageStackPos >= iPageStack.count()) {
|
||||||
|
iPageStackPos = iPageStack.count() - 1;
|
||||||
|
}
|
||||||
// Refcounted BooksBook objects are managed by C++ code
|
// Refcounted BooksBook objects are managed by C++ code
|
||||||
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
|
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||||
}
|
}
|
||||||
|
@ -339,6 +370,7 @@ BooksBook::BooksBook(const BooksStorage& aStorage, QString aRelativePath,
|
||||||
void BooksBook::init()
|
void BooksBook::init()
|
||||||
{
|
{
|
||||||
iFontSizeAdjust = 0;
|
iFontSizeAdjust = 0;
|
||||||
|
iPageStackPos = 0;
|
||||||
iCoverTask = NULL;
|
iCoverTask = NULL;
|
||||||
iCoverTasksDone = false;
|
iCoverTasksDone = false;
|
||||||
iCopyingOut = false;
|
iCopyingOut = false;
|
||||||
|
@ -419,10 +451,23 @@ bool BooksBook::setFontSizeAdjust(int aFontSizeAdjust)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooksBook::setLastPos(const BooksPos& aPos)
|
void BooksBook::setPageStack(BooksPos::List aStack, int aStackPos)
|
||||||
{
|
{
|
||||||
if (iLastPos != aPos) {
|
if (aStackPos < 0) {
|
||||||
iLastPos = aPos;
|
aStackPos = 0;
|
||||||
|
} else if (aStackPos >= aStack.count()) {
|
||||||
|
aStackPos = aStack.count() - 1;
|
||||||
|
}
|
||||||
|
bool changed = false;
|
||||||
|
if (iPageStack != aStack) {
|
||||||
|
iPageStack = aStack;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (iPageStackPos != aStackPos) {
|
||||||
|
iPageStackPos = aStackPos;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
requestSave();
|
requestSave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -536,8 +581,14 @@ void BooksBook::saveState()
|
||||||
if (!iStateFilePath.isEmpty()) {
|
if (!iStateFilePath.isEmpty()) {
|
||||||
QVariantMap state;
|
QVariantMap state;
|
||||||
HarbourJson::load(iStateFilePath, state);
|
HarbourJson::load(iStateFilePath, state);
|
||||||
state.insert(BOOK_STATE_POSITION, iLastPos.toVariant());
|
QVariantList positions;
|
||||||
|
const int n = iPageStack.count();
|
||||||
|
for (int i=0; i<n; i++) positions.append(iPageStack.at(i).toVariant());
|
||||||
|
state.insert(BOOK_STATE_POSITION, positions);
|
||||||
state.insert(BOOK_STATE_FONT_SIZE_ADJUST, iFontSizeAdjust);
|
state.insert(BOOK_STATE_FONT_SIZE_ADJUST, iFontSizeAdjust);
|
||||||
|
#ifdef BOOK_STATE_PAGE_STACK_INDEX
|
||||||
|
state.insert(BOOK_STATE_PAGE_STACK_INDEX, iPageStackPos);
|
||||||
|
#endif
|
||||||
if (HarbourJson::save(iStateFilePath, state)) {
|
if (HarbourJson::save(iStateFilePath, state)) {
|
||||||
HDEBUG("wrote" << iStateFilePath);
|
HDEBUG("wrote" << iStateFilePath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
* notice, this list of conditions and the following disclaimer in
|
* notice, this list of conditions and the following disclaimer in
|
||||||
* the documentation and/or other materials provided with the
|
* the documentation and/or other materials provided with the
|
||||||
* distribution.
|
* distribution.
|
||||||
* * Neither the name of Nemo Mobile nor the names of its contributors
|
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||||
* may be used to endorse or promote products derived from this
|
* may be used to endorse or promote products derived from this
|
||||||
* software without specific prior written permission.
|
* software without specific prior written permission.
|
||||||
*
|
*
|
||||||
|
@ -74,16 +74,17 @@ public:
|
||||||
static BooksBook* newBook(const BooksStorage& aStorage, QString aRelPath,
|
static BooksBook* newBook(const BooksStorage& aStorage, QString aRelPath,
|
||||||
QString aFileName);
|
QString aFileName);
|
||||||
|
|
||||||
QString title() const { return iTitle; }
|
QString title() const;
|
||||||
QString authors() const { return iAuthors; }
|
QString authors() const;
|
||||||
int fontSizeAdjust() const { return iFontSizeAdjust; }
|
int fontSizeAdjust() const;
|
||||||
bool setFontSizeAdjust(int aFontSizeAdjust);
|
bool setFontSizeAdjust(int aFontSizeAdjust);
|
||||||
BooksPos lastPos() const { return iLastPos; }
|
int pageStackPos() const;
|
||||||
void setLastPos(const BooksPos& aPos);
|
BooksPos::List pageStack() const;
|
||||||
shared_ptr<Book> bookRef() const { return iBook; }
|
void setPageStack(BooksPos::List aStack, int aStackPos);
|
||||||
|
shared_ptr<Book> bookRef() const;
|
||||||
|
|
||||||
bool copyingOut() const { return iCopyingOut; }
|
bool copyingOut() const;
|
||||||
bool loadingCover() const { return !iCoverTasksDone; }
|
bool loadingCover() const;
|
||||||
bool hasCoverImage() const;
|
bool hasCoverImage() const;
|
||||||
bool requestCoverImage();
|
bool requestCoverImage();
|
||||||
void cancelCoverRequest();
|
void cancelCoverRequest();
|
||||||
|
@ -129,7 +130,8 @@ private:
|
||||||
private:
|
private:
|
||||||
QAtomicInt iRef;
|
QAtomicInt iRef;
|
||||||
int iFontSizeAdjust;
|
int iFontSizeAdjust;
|
||||||
BooksPos iLastPos;
|
int iPageStackPos;
|
||||||
|
BooksPos::List iPageStack;
|
||||||
BooksStorage iStorage;
|
BooksStorage iStorage;
|
||||||
shared_ptr<Book> iBook;
|
shared_ptr<Book> iBook;
|
||||||
QImage iCoverImage;
|
QImage iCoverImage;
|
||||||
|
@ -149,6 +151,22 @@ private:
|
||||||
|
|
||||||
QML_DECLARE_TYPE(BooksBook)
|
QML_DECLARE_TYPE(BooksBook)
|
||||||
|
|
||||||
|
inline QString BooksBook::title() const
|
||||||
|
{ return iTitle; }
|
||||||
|
inline QString BooksBook::authors() const
|
||||||
|
{ return iAuthors; }
|
||||||
|
inline int BooksBook::fontSizeAdjust() const
|
||||||
|
{ return iFontSizeAdjust; }
|
||||||
|
inline int BooksBook::pageStackPos() const
|
||||||
|
{ return iPageStackPos; }
|
||||||
|
inline BooksPos::List BooksBook::pageStack() const
|
||||||
|
{ return iPageStack; }
|
||||||
|
inline shared_ptr<Book> BooksBook::bookRef() const
|
||||||
|
{ return iBook; }
|
||||||
|
inline bool BooksBook::copyingOut() const
|
||||||
|
{ return iCopyingOut; }
|
||||||
|
inline bool BooksBook::loadingCover() const
|
||||||
|
{ return !iCoverTasksDone; }
|
||||||
inline bool BooksBook::isCanceled(CopyOperation* aObserver)
|
inline bool BooksBook::isCanceled(CopyOperation* aObserver)
|
||||||
{ return aObserver && aObserver->isCanceled(); }
|
{ return aObserver && aObserver->isCanceled(); }
|
||||||
inline QImage BooksBook::coverImage() const
|
inline QImage BooksBook::coverImage() const
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -45,10 +45,6 @@ class BooksBookModel::Data {
|
||||||
public:
|
public:
|
||||||
Data(int aWidth, int aHeight) : iWidth(aWidth), iHeight(aHeight) {}
|
Data(int aWidth, int aHeight) : iWidth(aWidth), iHeight(aHeight) {}
|
||||||
|
|
||||||
int pickPage(const BooksPos& aPagePos) const;
|
|
||||||
int pickPage(const BooksPos& aPagePos, const BooksPos& aNextPagePos,
|
|
||||||
int aPageCount) const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int iWidth;
|
int iWidth;
|
||||||
int iHeight;
|
int iHeight;
|
||||||
|
@ -56,65 +52,17 @@ public:
|
||||||
BooksPos::List iPageMarks;
|
BooksPos::List iPageMarks;
|
||||||
};
|
};
|
||||||
|
|
||||||
int BooksBookModel::Data::pickPage(const BooksPos& aPagePos) const
|
|
||||||
{
|
|
||||||
int page = 0;
|
|
||||||
if (aPagePos.valid()) {
|
|
||||||
BooksPos::ConstIterator it = qFind(iPageMarks, aPagePos);
|
|
||||||
if (it == iPageMarks.end()) {
|
|
||||||
it = qUpperBound(iPageMarks, aPagePos);
|
|
||||||
page = (int)(it - iPageMarks.begin()) - 1;
|
|
||||||
HDEBUG("using page" << page << "for" << aPagePos);
|
|
||||||
} else {
|
|
||||||
page = it - iPageMarks.begin();
|
|
||||||
HDEBUG("found" << aPagePos << "at page" << page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BooksBookModel::Data::pickPage(const BooksPos& aPagePos,
|
|
||||||
const BooksPos& aNextPagePos, int aPageCount) const
|
|
||||||
{
|
|
||||||
int page = 0;
|
|
||||||
if (aPagePos.valid()) {
|
|
||||||
if (!aNextPagePos.valid()) {
|
|
||||||
// Last page stays the last
|
|
||||||
page = iPageMarks.count() - 1;
|
|
||||||
HDEBUG("last page" << page);
|
|
||||||
} else {
|
|
||||||
BooksPos::ConstIterator it = qFind(iPageMarks, aPagePos);
|
|
||||||
if (it == iPageMarks.end()) {
|
|
||||||
// Two 90-degrees rotations should return the reader
|
|
||||||
// back to the same page. That's what this is about.
|
|
||||||
const BooksPos& pos = (iPageMarks.count() > aPageCount) ?
|
|
||||||
aPagePos : aNextPagePos;
|
|
||||||
it = qUpperBound(iPageMarks, pos);
|
|
||||||
page = (int)(it - iPageMarks.begin());
|
|
||||||
if (page > 0) page--;
|
|
||||||
HDEBUG("using page" << page << "for" << pos);
|
|
||||||
} else {
|
|
||||||
page = it - iPageMarks.begin();
|
|
||||||
HDEBUG("found" << aPagePos << "at page" << page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// BooksBookModel::Task
|
// BooksBookModel::PagingTask
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
class BooksBookModel::Task : public BooksTask
|
class BooksBookModel::PagingTask : public BooksTask
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Task(BooksBookModel* aReceiver, shared_ptr<Book> aBook,
|
PagingTask(BooksBookModel* aReceiver, shared_ptr<Book> aBook);
|
||||||
const BooksPos& aPagePos, const BooksPos& aNextPagePos,
|
~PagingTask();
|
||||||
const BooksPos& aLastPos, int aPageCount);
|
|
||||||
~Task();
|
|
||||||
|
|
||||||
void performTask();
|
void performTask();
|
||||||
|
|
||||||
|
@ -127,38 +75,27 @@ public:
|
||||||
BooksMargins iMargins;
|
BooksMargins iMargins;
|
||||||
BooksPaintContext iPaint;
|
BooksPaintContext iPaint;
|
||||||
BooksBookModel::Data* iData;
|
BooksBookModel::Data* iData;
|
||||||
BooksPos iPagePos;
|
|
||||||
BooksPos iNextPagePos;
|
|
||||||
BooksPos iLastPos;
|
|
||||||
int iOldPageCount;
|
|
||||||
int iPage;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BooksBookModel::Task::Task(BooksBookModel* aModel,
|
BooksBookModel::PagingTask::PagingTask(BooksBookModel* aModel,
|
||||||
shared_ptr<Book> aBook, const BooksPos& aPagePos,
|
shared_ptr<Book> aBook) :
|
||||||
const BooksPos& aNextPagePos, const BooksPos& aLastPos, int aPageCount) :
|
|
||||||
iBook(aBook),
|
iBook(aBook),
|
||||||
iTextStyle(aModel->textStyle()),
|
iTextStyle(aModel->textStyle()),
|
||||||
iMargins(aModel->margins()),
|
iMargins(aModel->margins()),
|
||||||
iPaint(aModel->width(), aModel->height()),
|
iPaint(aModel->width(), aModel->height()),
|
||||||
iData(NULL),
|
iData(NULL)
|
||||||
iPagePos(aPagePos),
|
|
||||||
iNextPagePos(aNextPagePos),
|
|
||||||
iLastPos(aLastPos),
|
|
||||||
iOldPageCount(aPageCount),
|
|
||||||
iPage(-1)
|
|
||||||
{
|
{
|
||||||
aModel->connect(this, SIGNAL(done()), SLOT(onResetDone()));
|
aModel->connect(this, SIGNAL(done()), SLOT(onResetDone()));
|
||||||
aModel->connect(this, SIGNAL(progress(int)), SLOT(onResetProgress(int)),
|
aModel->connect(this, SIGNAL(progress(int)), SLOT(onResetProgress(int)),
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
BooksBookModel::Task::~Task()
|
BooksBookModel::PagingTask::~PagingTask()
|
||||||
{
|
{
|
||||||
delete iData;
|
delete iData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooksBookModel::Task::performTask()
|
void BooksBookModel::PagingTask::performTask()
|
||||||
{
|
{
|
||||||
if (!isCanceled()) {
|
if (!isCanceled()) {
|
||||||
iData = new BooksBookModel::Data(iPaint.width(), iPaint.height());
|
iData = new BooksBookModel::Data(iPaint.width(), iPaint.height());
|
||||||
|
@ -183,9 +120,6 @@ void BooksBookModel::Task::performTask()
|
||||||
if (!isCanceled()) {
|
if (!isCanceled()) {
|
||||||
HDEBUG(iData->iPageMarks.count() << "page(s)" << qPrintable(
|
HDEBUG(iData->iPageMarks.count() << "page(s)" << qPrintable(
|
||||||
QString("%1x%2").arg(iData->iWidth).arg(iData->iHeight)));
|
QString("%1x%2").arg(iData->iWidth).arg(iData->iHeight)));
|
||||||
iPage = iPagePos.valid() ?
|
|
||||||
iData->pickPage(iPagePos, iNextPagePos, iOldPageCount) :
|
|
||||||
iData->pickPage(iLastPos);
|
|
||||||
} else {
|
} else {
|
||||||
HDEBUG("giving up" << qPrintable(QString("%1x%2").arg(iPaint.width()).
|
HDEBUG("giving up" << qPrintable(QString("%1x%2").arg(iPaint.width()).
|
||||||
arg(iPaint.height())) << "paging");
|
arg(iPaint.height())) << "paging");
|
||||||
|
@ -203,17 +137,19 @@ enum BooksBookModelRole {
|
||||||
BooksBookModel::BooksBookModel(QObject* aParent) :
|
BooksBookModel::BooksBookModel(QObject* aParent) :
|
||||||
QAbstractListModel(aParent),
|
QAbstractListModel(aParent),
|
||||||
iResetReason(ReasonUnknown),
|
iResetReason(ReasonUnknown),
|
||||||
iCurrentPage(-1),
|
|
||||||
iProgress(0),
|
iProgress(0),
|
||||||
iBook(NULL),
|
iBook(NULL),
|
||||||
iTask(NULL),
|
iPagingTask(NULL),
|
||||||
iData(NULL),
|
iData(NULL),
|
||||||
iData2(NULL),
|
iData2(NULL),
|
||||||
iSettings(BooksSettings::sharedInstance()),
|
iSettings(BooksSettings::sharedInstance()),
|
||||||
iTaskQueue(BooksTaskQueue::defaultQueue())
|
iTaskQueue(BooksTaskQueue::defaultQueue()),
|
||||||
|
iPageStack(new BooksPageStack(this))
|
||||||
{
|
{
|
||||||
iTextStyle = iSettings->textStyle(fontSizeAdjust());
|
iTextStyle = iSettings->textStyle(fontSizeAdjust());
|
||||||
connect(iSettings.data(), SIGNAL(textStyleChanged()), SLOT(onTextStyleChanged()));
|
connect(iSettings.data(), SIGNAL(textStyleChanged()), SLOT(onTextStyleChanged()));
|
||||||
|
connect(iPageStack, SIGNAL(changed()), SLOT(onPageStackChanged()));
|
||||||
|
connect(iPageStack, SIGNAL(currentIndexChanged()), SLOT(onPageStackChanged()));
|
||||||
HDEBUG("created");
|
HDEBUG("created");
|
||||||
#if QT_VERSION < 0x050000
|
#if QT_VERSION < 0x050000
|
||||||
setRoleNames(roleNames());
|
setRoleNames(roleNames());
|
||||||
|
@ -222,7 +158,7 @@ BooksBookModel::BooksBookModel(QObject* aParent) :
|
||||||
|
|
||||||
BooksBookModel::~BooksBookModel()
|
BooksBookModel::~BooksBookModel()
|
||||||
{
|
{
|
||||||
if (iTask) iTask->release(this);
|
if (iPagingTask) iPagingTask->release(this);
|
||||||
if (iBook) {
|
if (iBook) {
|
||||||
iBook->disconnect(this);
|
iBook->disconnect(this);
|
||||||
iBook->release();
|
iBook->release();
|
||||||
|
@ -235,7 +171,6 @@ BooksBookModel::~BooksBookModel()
|
||||||
|
|
||||||
void BooksBookModel::setBook(BooksBook* aBook)
|
void BooksBookModel::setBook(BooksBook* aBook)
|
||||||
{
|
{
|
||||||
shared_ptr<Book> oldBook;
|
|
||||||
shared_ptr<Book> newBook;
|
shared_ptr<Book> newBook;
|
||||||
if (iBook != aBook) {
|
if (iBook != aBook) {
|
||||||
const QString oldTitle(iTitle);
|
const QString oldTitle(iTitle);
|
||||||
|
@ -246,14 +181,16 @@ void BooksBookModel::setBook(BooksBook* aBook)
|
||||||
if (aBook) {
|
if (aBook) {
|
||||||
(iBook = aBook)->retain();
|
(iBook = aBook)->retain();
|
||||||
iBookRef = newBook;
|
iBookRef = newBook;
|
||||||
iTitle = iBook->title();
|
iTitle = aBook->title();
|
||||||
iTextStyle = iSettings->textStyle(fontSizeAdjust());
|
iTextStyle = iSettings->textStyle(fontSizeAdjust());
|
||||||
connect(iBook, SIGNAL(fontSizeAdjustChanged()), SLOT(onTextStyleChanged()));
|
iPageStack->setStack(aBook->pageStack(), aBook->pageStackPos());
|
||||||
|
connect(aBook, SIGNAL(fontSizeAdjustChanged()), SLOT(onTextStyleChanged()));
|
||||||
HDEBUG(iTitle);
|
HDEBUG(iTitle);
|
||||||
} else {
|
} else {
|
||||||
iBook = NULL;
|
iBook = NULL;
|
||||||
iBookRef.reset();
|
iBookRef.reset();
|
||||||
iTitle = QString();
|
iTitle = QString();
|
||||||
|
iPageStack->clear();
|
||||||
HDEBUG("<none>");
|
HDEBUG("<none>");
|
||||||
}
|
}
|
||||||
startReset(ReasonLoading, true);
|
startReset(ReasonLoading, true);
|
||||||
|
@ -268,7 +205,7 @@ void BooksBookModel::setBook(BooksBook* aBook)
|
||||||
|
|
||||||
bool BooksBookModel::loading() const
|
bool BooksBookModel::loading() const
|
||||||
{
|
{
|
||||||
return (iTask != NULL);
|
return (iPagingTask != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BooksBookModel::increaseFontSize()
|
bool BooksBookModel::increaseFontSize()
|
||||||
|
@ -281,19 +218,12 @@ bool BooksBookModel::decreaseFontSize()
|
||||||
return iBook && iBook->setFontSizeAdjust(iBook->fontSizeAdjust()-1);
|
return iBook && iBook->setFontSizeAdjust(iBook->fontSizeAdjust()-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooksBookModel::setCurrentPage(int aPage)
|
void BooksBookModel::onPageStackChanged()
|
||||||
{
|
{
|
||||||
if (iCurrentPage != aPage) {
|
if (iBook) {
|
||||||
iCurrentPage = aPage;
|
BooksPos::Stack stack = iPageStack->getStack();
|
||||||
if (iData &&
|
HDEBUG(stack.iList << stack.iPos);
|
||||||
iCurrentPage >= 0 &&
|
iBook->setPageStack(stack.iList, stack.iPos);
|
||||||
iCurrentPage < iData->iPageMarks.count()) {
|
|
||||||
iBook->setLastPos(iData->iPageMarks.at(iCurrentPage));
|
|
||||||
HDEBUG(aPage << iBook->lastPos());
|
|
||||||
} else {
|
|
||||||
HDEBUG(aPage);
|
|
||||||
}
|
|
||||||
Q_EMIT currentPageChanged();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,24 +244,18 @@ int BooksBookModel::fontSizeAdjust() const
|
||||||
|
|
||||||
BooksPos BooksBookModel::pageMark(int aPage) const
|
BooksPos BooksBookModel::pageMark(int aPage) const
|
||||||
{
|
{
|
||||||
if (aPage >= 0 && iData) {
|
return iData ? BooksPos::posAt(iData->iPageMarks, aPage) : BooksPos();
|
||||||
const int n = iData->iPageMarks.count();
|
|
||||||
if (aPage < n) {
|
|
||||||
return iData->iPageMarks.at(aPage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return BooksPos();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int BooksBookModel::linkToPage(const std::string& aLink) const
|
BooksPos BooksBookModel::linkPosition(const std::string& aLink) const
|
||||||
{
|
{
|
||||||
if (iData && !iData->iBookModel.isNull()) {
|
if (iData && !iData->iBookModel.isNull()) {
|
||||||
BookModel::Label label = iData->iBookModel->label(aLink);
|
BookModel::Label label = iData->iBookModel->label(aLink);
|
||||||
if (label.ParagraphNumber >= 0) {
|
if (label.ParagraphNumber >= 0) {
|
||||||
return iData->pickPage(BooksPos(label.ParagraphNumber, 0, 0));
|
return BooksPos(label.ParagraphNumber, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return BooksPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<BookModel> BooksBookModel::bookModel() const
|
shared_ptr<BookModel> BooksBookModel::bookModel() const
|
||||||
|
@ -410,6 +334,7 @@ void BooksBookModel::updateModel(int aPrevPageCount)
|
||||||
{
|
{
|
||||||
const int newPageCount = pageCount();
|
const int newPageCount = pageCount();
|
||||||
if (aPrevPageCount != newPageCount) {
|
if (aPrevPageCount != newPageCount) {
|
||||||
|
HDEBUG(aPrevPageCount << "->" << newPageCount);
|
||||||
if (newPageCount > aPrevPageCount) {
|
if (newPageCount > aPrevPageCount) {
|
||||||
beginInsertRows(QModelIndex(), aPrevPageCount, newPageCount-1);
|
beginInsertRows(QModelIndex(), aPrevPageCount, newPageCount-1);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
@ -433,36 +358,20 @@ void BooksBookModel::setSize(QSize aSize)
|
||||||
} else if (iData2 && iData2->iWidth == w && iData2->iHeight == h) {
|
} else if (iData2 && iData2->iWidth == w && iData2->iHeight == h) {
|
||||||
HDEBUG("switching to backup layout");
|
HDEBUG("switching to backup layout");
|
||||||
const int oldModelPageCount = pageCount();
|
const int oldModelPageCount = pageCount();
|
||||||
int oldPageCount;
|
|
||||||
BooksPos page1, page2;
|
|
||||||
if (iTask) {
|
|
||||||
// Layout has been switched back before the paging task
|
|
||||||
// has completed
|
|
||||||
HDEBUG("not so fast please...");
|
|
||||||
oldPageCount = iTask->iOldPageCount;
|
|
||||||
page1 = iTask->iPagePos;
|
|
||||||
page2 = iTask->iNextPagePos;
|
|
||||||
} else {
|
|
||||||
oldPageCount = oldModelPageCount;
|
|
||||||
page1 = pageMark(iCurrentPage);
|
|
||||||
page2 = pageMark(iCurrentPage+1);
|
|
||||||
}
|
|
||||||
Data* tmp = iData;
|
Data* tmp = iData;
|
||||||
iData = iData2;
|
iData = iData2;
|
||||||
iData2 = tmp;
|
iData2 = tmp;
|
||||||
if (iData) {
|
// Cancel unnecessary paging task
|
||||||
// Cancel unnecessary paging task
|
BooksLoadingSignalBlocker block(this);
|
||||||
if (iTask) {
|
if (iPagingTask) {
|
||||||
BooksLoadingSignalBlocker block(this);
|
HDEBUG("not so fast please...");
|
||||||
iTask->release(this);
|
iPagingTask->release(this);
|
||||||
iTask = NULL;
|
iPagingTask = NULL;
|
||||||
}
|
|
||||||
updateModel(oldModelPageCount);
|
|
||||||
Q_EMIT pageMarksChanged();
|
|
||||||
Q_EMIT jumpToPage(iData->pickPage(page1, page2, oldPageCount));
|
|
||||||
} else {
|
|
||||||
startReset(ReasonUnknown, false);
|
|
||||||
}
|
}
|
||||||
|
updateModel(oldModelPageCount);
|
||||||
|
iPageStack->setPageMarks(iData->iPageMarks);
|
||||||
|
Q_EMIT pageMarksChanged();
|
||||||
|
Q_EMIT jumpToPage(iPageStack->currentPage());
|
||||||
} else {
|
} else {
|
||||||
startReset(ReasonUnknown, false);
|
startReset(ReasonUnknown, false);
|
||||||
}
|
}
|
||||||
|
@ -487,9 +396,8 @@ void BooksBookModel::onTextStyleChanged()
|
||||||
|
|
||||||
void BooksBookModel::startReset(ResetReason aResetReason, bool aFullReset)
|
void BooksBookModel::startReset(ResetReason aResetReason, bool aFullReset)
|
||||||
{
|
{
|
||||||
|
BooksPos dummy;
|
||||||
BooksLoadingSignalBlocker block(this);
|
BooksLoadingSignalBlocker block(this);
|
||||||
const BooksPos thisPage = pageMark(iCurrentPage);
|
|
||||||
const BooksPos nextPage = pageMark(iCurrentPage+1);
|
|
||||||
if (aResetReason == ReasonUnknown) {
|
if (aResetReason == ReasonUnknown) {
|
||||||
if (iResetReason == ReasonUnknown) {
|
if (iResetReason == ReasonUnknown) {
|
||||||
if (!iData && !iData2) {
|
if (!iData && !iData2) {
|
||||||
|
@ -499,9 +407,9 @@ void BooksBookModel::startReset(ResetReason aResetReason, bool aFullReset)
|
||||||
aResetReason = iResetReason;
|
aResetReason = iResetReason;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (iTask) {
|
if (iPagingTask) {
|
||||||
iTask->release(this);
|
iPagingTask->release(this);
|
||||||
iTask = NULL;
|
iPagingTask = NULL;
|
||||||
}
|
}
|
||||||
const int oldPageCount(pageCount());
|
const int oldPageCount(pageCount());
|
||||||
if (oldPageCount > 0) {
|
if (oldPageCount > 0) {
|
||||||
|
@ -520,9 +428,8 @@ void BooksBookModel::startReset(ResetReason aResetReason, bool aFullReset)
|
||||||
if (iBook && width() > 0 && height() > 0) {
|
if (iBook && width() > 0 && height() > 0) {
|
||||||
HDEBUG("starting" << qPrintable(QString("%1x%2").arg(width()).
|
HDEBUG("starting" << qPrintable(QString("%1x%2").arg(width()).
|
||||||
arg(height())) << "paging");
|
arg(height())) << "paging");
|
||||||
iTask = new Task(this, iBook->bookRef(), thisPage, nextPage,
|
iPagingTask = new PagingTask(this, iBook->bookRef());
|
||||||
iBook->lastPos(), oldPageCount);
|
iTaskQueue->submit(iPagingTask);
|
||||||
iTaskQueue->submit(iTask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldPageCount > 0) {
|
if (oldPageCount > 0) {
|
||||||
|
@ -531,11 +438,6 @@ void BooksBookModel::startReset(ResetReason aResetReason, bool aFullReset)
|
||||||
Q_EMIT pageCountChanged();
|
Q_EMIT pageCountChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iCurrentPage != 0) {
|
|
||||||
iCurrentPage = 0;
|
|
||||||
Q_EMIT currentPageChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iProgress != 0) {
|
if (iProgress != 0) {
|
||||||
iProgress = 0;
|
iProgress = 0;
|
||||||
Q_EMIT progressChanged();
|
Q_EMIT progressChanged();
|
||||||
|
@ -551,7 +453,7 @@ void BooksBookModel::onResetProgress(int aProgress)
|
||||||
{
|
{
|
||||||
// progress -> onResetProgress is a queued connection, we may received
|
// progress -> onResetProgress is a queued connection, we may received
|
||||||
// this event from the task that has already been canceled.
|
// this event from the task that has already been canceled.
|
||||||
if (iTask == sender() && aProgress > iProgress) {
|
if (iPagingTask == sender() && aProgress > iProgress) {
|
||||||
iProgress = aProgress;
|
iProgress = aProgress;
|
||||||
Q_EMIT progressChanged();
|
Q_EMIT progressChanged();
|
||||||
}
|
}
|
||||||
|
@ -559,22 +461,22 @@ void BooksBookModel::onResetProgress(int aProgress)
|
||||||
|
|
||||||
void BooksBookModel::onResetDone()
|
void BooksBookModel::onResetDone()
|
||||||
{
|
{
|
||||||
HASSERT(sender() == iTask);
|
HASSERT(sender() == iPagingTask);
|
||||||
HASSERT(iTask->iData);
|
HASSERT(iPagingTask->iData);
|
||||||
HASSERT(!iData);
|
HASSERT(!iData);
|
||||||
|
|
||||||
const int oldPageCount(pageCount());
|
const int oldPageCount(pageCount());
|
||||||
shared_ptr<BookModel> oldBookModel(bookModel());
|
shared_ptr<BookModel> oldBookModel(bookModel());
|
||||||
BooksLoadingSignalBlocker block(this);
|
BooksLoadingSignalBlocker block(this);
|
||||||
int page = iTask->iPage;
|
|
||||||
|
|
||||||
iData = iTask->iData;
|
iData = iPagingTask->iData;
|
||||||
iTask->iData = NULL;
|
iPagingTask->iData = NULL;
|
||||||
iTask->release(this);
|
iPagingTask->release(this);
|
||||||
iTask = NULL;
|
iPagingTask = NULL;
|
||||||
|
|
||||||
updateModel(oldPageCount);
|
updateModel(oldPageCount);
|
||||||
Q_EMIT jumpToPage(page);
|
iPageStack->setPageMarks(iData->iPageMarks);
|
||||||
|
Q_EMIT jumpToPage(iPageStack->currentPage());
|
||||||
Q_EMIT pageMarksChanged();
|
Q_EMIT pageMarksChanged();
|
||||||
if (oldBookModel != bookModel()) {
|
if (oldBookModel != bookModel()) {
|
||||||
Q_EMIT bookModelChanged();
|
Q_EMIT bookModelChanged();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -42,6 +42,7 @@
|
||||||
#include "BooksPos.h"
|
#include "BooksPos.h"
|
||||||
#include "BooksPaintContext.h"
|
#include "BooksPaintContext.h"
|
||||||
#include "BooksLoadingProperty.h"
|
#include "BooksLoadingProperty.h"
|
||||||
|
#include "BooksPageStack.h"
|
||||||
|
|
||||||
#include "ZLTextStyle.h"
|
#include "ZLTextStyle.h"
|
||||||
#include "bookmodel/BookModel.h"
|
#include "bookmodel/BookModel.h"
|
||||||
|
@ -63,11 +64,11 @@ class BooksBookModel: public QAbstractListModel, private BooksLoadingProperty
|
||||||
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
|
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
|
||||||
Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
|
Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
|
||||||
Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged)
|
Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged)
|
||||||
Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged)
|
|
||||||
Q_PROPERTY(int leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
|
Q_PROPERTY(int leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
|
||||||
Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
|
Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
|
||||||
Q_PROPERTY(int topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
|
Q_PROPERTY(int topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
|
||||||
Q_PROPERTY(int bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
|
Q_PROPERTY(int bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
|
||||||
|
Q_PROPERTY(BooksPageStack* pageStack READ pageStack CONSTANT)
|
||||||
Q_PROPERTY(BooksBook* book READ book WRITE setBook NOTIFY bookChanged)
|
Q_PROPERTY(BooksBook* book READ book WRITE setBook NOTIFY bookChanged)
|
||||||
Q_PROPERTY(ResetReason resetReason READ resetReason NOTIFY resetReasonChanged)
|
Q_PROPERTY(ResetReason resetReason READ resetReason NOTIFY resetReasonChanged)
|
||||||
|
|
||||||
|
@ -88,25 +89,23 @@ public:
|
||||||
|
|
||||||
bool loading() const;
|
bool loading() const;
|
||||||
int pageCount() const;
|
int pageCount() const;
|
||||||
int progress() const { return iProgress; }
|
int progress() const;
|
||||||
QString title() const { return iTitle; }
|
QString title() const;
|
||||||
int width() const { return iSize.width(); }
|
int width() const;
|
||||||
int height() const { return iSize.height(); }
|
int height() const;
|
||||||
ResetReason resetReason() const { return iResetReason; }
|
ResetReason resetReason() const;
|
||||||
|
BooksPageStack* pageStack() const;
|
||||||
|
|
||||||
QSize size() const { return iSize; }
|
QSize size() const;
|
||||||
void setSize(QSize aSize);
|
void setSize(QSize aSize);
|
||||||
|
|
||||||
int currentPage() const { return iCurrentPage; }
|
BooksBook* book() const;
|
||||||
void setCurrentPage(int aPage);
|
|
||||||
|
|
||||||
BooksBook* book() const { return iBook; }
|
|
||||||
void setBook(BooksBook* aBook);
|
void setBook(BooksBook* aBook);
|
||||||
|
|
||||||
int leftMargin() const { return iMargins.iLeft; }
|
int leftMargin() const;
|
||||||
int rightMargin() const { return iMargins.iRight; }
|
int rightMargin() const;
|
||||||
int topMargin() const { return iMargins.iTop; }
|
int topMargin() const;
|
||||||
int bottomMargin() const { return iMargins.iBottom; }
|
int bottomMargin() const;
|
||||||
|
|
||||||
void setLeftMargin(int aMargin);
|
void setLeftMargin(int aMargin);
|
||||||
void setRightMargin(int aMargin);
|
void setRightMargin(int aMargin);
|
||||||
|
@ -115,14 +114,14 @@ public:
|
||||||
|
|
||||||
BooksPos::List pageMarks() const;
|
BooksPos::List pageMarks() const;
|
||||||
BooksPos pageMark(int aPage) const;
|
BooksPos pageMark(int aPage) const;
|
||||||
BooksMargins margins() const { return iMargins; }
|
BooksMargins margins() const;
|
||||||
shared_ptr<Book> bookRef() const { return iBookRef; }
|
shared_ptr<Book> bookRef() const;
|
||||||
shared_ptr<BookModel> bookModel() const;
|
shared_ptr<BookModel> bookModel() const;
|
||||||
shared_ptr<ZLTextModel> bookTextModel() const;
|
shared_ptr<ZLTextModel> bookTextModel() const;
|
||||||
shared_ptr<ZLTextModel> contentsModel() const;
|
shared_ptr<ZLTextModel> contentsModel() const;
|
||||||
shared_ptr<ZLTextModel> footnoteModel(const std::string& aId) const;
|
shared_ptr<ZLTextModel> footnoteModel(const std::string& aId) const;
|
||||||
shared_ptr<ZLTextStyle> textStyle() const { return iTextStyle; }
|
shared_ptr<ZLTextStyle> textStyle() const;
|
||||||
int linkToPage(const std::string& aLink) const;
|
BooksPos linkPosition(const std::string& aLink) const;
|
||||||
int fontSizeAdjust() const;
|
int fontSizeAdjust() const;
|
||||||
|
|
||||||
// QAbstractListModel
|
// QAbstractListModel
|
||||||
|
@ -139,6 +138,7 @@ private Q_SLOTS:
|
||||||
void onResetProgress(int aProgress);
|
void onResetProgress(int aProgress);
|
||||||
void onResetDone();
|
void onResetDone();
|
||||||
void onTextStyleChanged();
|
void onTextStyleChanged();
|
||||||
|
void onPageStackChanged();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void sizeChanged();
|
void sizeChanged();
|
||||||
|
@ -149,7 +149,6 @@ Q_SIGNALS:
|
||||||
void pageCountChanged();
|
void pageCountChanged();
|
||||||
void pageMarksChanged();
|
void pageMarksChanged();
|
||||||
void progressChanged();
|
void progressChanged();
|
||||||
void currentPageChanged();
|
|
||||||
void leftMarginChanged();
|
void leftMarginChanged();
|
||||||
void rightMarginChanged();
|
void rightMarginChanged();
|
||||||
void topMarginChanged();
|
void topMarginChanged();
|
||||||
|
@ -160,24 +159,55 @@ Q_SIGNALS:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Data;
|
class Data;
|
||||||
class Task;
|
class PagingTask;
|
||||||
|
|
||||||
ResetReason iResetReason;
|
ResetReason iResetReason;
|
||||||
int iCurrentPage;
|
|
||||||
int iProgress;
|
int iProgress;
|
||||||
QSize iSize;
|
QSize iSize;
|
||||||
QString iTitle;
|
QString iTitle;
|
||||||
BooksMargins iMargins;
|
BooksMargins iMargins;
|
||||||
BooksBook* iBook;
|
BooksBook* iBook;
|
||||||
shared_ptr<Book> iBookRef;
|
shared_ptr<Book> iBookRef;
|
||||||
Task* iTask;
|
PagingTask* iPagingTask;
|
||||||
Data* iData;
|
Data* iData;
|
||||||
Data* iData2;
|
Data* iData2;
|
||||||
QSharedPointer<BooksSettings> iSettings;
|
QSharedPointer<BooksSettings> iSettings;
|
||||||
shared_ptr<BooksTaskQueue> iTaskQueue;
|
shared_ptr<BooksTaskQueue> iTaskQueue;
|
||||||
shared_ptr<ZLTextStyle> iTextStyle;
|
shared_ptr<ZLTextStyle> iTextStyle;
|
||||||
|
BooksPageStack* iPageStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
QML_DECLARE_TYPE(BooksBookModel)
|
QML_DECLARE_TYPE(BooksBookModel)
|
||||||
|
|
||||||
|
inline int BooksBookModel::progress() const
|
||||||
|
{ return iProgress; }
|
||||||
|
inline QString BooksBookModel::title() const
|
||||||
|
{ return iTitle; }
|
||||||
|
inline int BooksBookModel::width() const
|
||||||
|
{ return iSize.width(); }
|
||||||
|
inline int BooksBookModel::height() const
|
||||||
|
{ return iSize.height(); }
|
||||||
|
inline BooksBookModel::ResetReason BooksBookModel::resetReason() const
|
||||||
|
{ return iResetReason; }
|
||||||
|
inline BooksPageStack* BooksBookModel::pageStack() const
|
||||||
|
{ return iPageStack; }
|
||||||
|
inline QSize BooksBookModel::size() const
|
||||||
|
{ return iSize; }
|
||||||
|
inline BooksBook* BooksBookModel::book() const
|
||||||
|
{ return iBook; }
|
||||||
|
inline int BooksBookModel::leftMargin() const
|
||||||
|
{ return iMargins.iLeft; }
|
||||||
|
inline int BooksBookModel::rightMargin() const
|
||||||
|
{ return iMargins.iRight; }
|
||||||
|
inline int BooksBookModel::topMargin() const
|
||||||
|
{ return iMargins.iTop; }
|
||||||
|
inline int BooksBookModel::bottomMargin() const
|
||||||
|
{ return iMargins.iBottom; }
|
||||||
|
inline BooksMargins BooksBookModel::margins() const
|
||||||
|
{ return iMargins; }
|
||||||
|
inline shared_ptr<Book> BooksBookModel::bookRef() const
|
||||||
|
{ return iBookRef; }
|
||||||
|
inline shared_ptr<ZLTextStyle> BooksBookModel::textStyle() const
|
||||||
|
{ return iTextStyle; }
|
||||||
|
|
||||||
#endif // BOOKS_BOOK_MODEL_H
|
#endif // BOOKS_BOOK_MODEL_H
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -37,6 +37,8 @@
|
||||||
|
|
||||||
#define LISTVIEW_CONTENT_X "contentX"
|
#define LISTVIEW_CONTENT_X "contentX"
|
||||||
#define LISTVIEW_CONTENT_Y "contentY"
|
#define LISTVIEW_CONTENT_Y "contentY"
|
||||||
|
#define LISTVIEW_CONTENT_WIDTH "contentWidth"
|
||||||
|
#define LISTVIEW_CONTENT_HEIGHT "contentHeight"
|
||||||
#define LISTVIEW_INDEX_AT "indexAt"
|
#define LISTVIEW_INDEX_AT "indexAt"
|
||||||
#define LISTVIEW_POSITION_VIEW_AT_INDEX "positionViewAtIndex"
|
#define LISTVIEW_POSITION_VIEW_AT_INDEX "positionViewAtIndex"
|
||||||
|
|
||||||
|
@ -48,7 +50,6 @@ BooksListWatcher::BooksListWatcher(QObject* aParent) :
|
||||||
iListView(NULL),
|
iListView(NULL),
|
||||||
iCenterMode(-1),
|
iCenterMode(-1),
|
||||||
iPositionIsChanging(false),
|
iPositionIsChanging(false),
|
||||||
iCanRetry(true),
|
|
||||||
iResizeTimer(new QTimer(this))
|
iResizeTimer(new QTimer(this))
|
||||||
{
|
{
|
||||||
iResizeTimer->setSingleShot(true);
|
iResizeTimer->setSingleShot(true);
|
||||||
|
@ -63,7 +64,6 @@ void BooksListWatcher::setListView(QQuickItem* aView)
|
||||||
if (iListView) iListView->disconnect(this);
|
if (iListView) iListView->disconnect(this);
|
||||||
iListView = aView;
|
iListView = aView;
|
||||||
iCenterMode = -1;
|
iCenterMode = -1;
|
||||||
iCanRetry = true;
|
|
||||||
if (iListView) {
|
if (iListView) {
|
||||||
connect(iListView,
|
connect(iListView,
|
||||||
SIGNAL(widthChanged()),
|
SIGNAL(widthChanged()),
|
||||||
|
@ -120,46 +120,47 @@ void BooksListWatcher::positionViewAtIndex(int aIndex)
|
||||||
{
|
{
|
||||||
if (iListView) {
|
if (iListView) {
|
||||||
HDEBUG(aIndex);
|
HDEBUG(aIndex);
|
||||||
if (iCenterMode < 0) {
|
doPositionViewAtIndex(aIndex);
|
||||||
bool ok = false;
|
}
|
||||||
const QMetaObject* metaObject = iListView->metaObject();
|
}
|
||||||
if (metaObject) {
|
|
||||||
int index = metaObject->indexOfEnumerator("PositionMode");
|
void BooksListWatcher::doPositionViewAtIndex(int aIndex)
|
||||||
if (index >= 0) {
|
{
|
||||||
QMetaEnum metaEnum = metaObject->enumerator(index);
|
if (iCenterMode < 0) {
|
||||||
int value = metaEnum.keyToValue("Center", &ok);
|
bool ok = false;
|
||||||
if (ok) {
|
const QMetaObject* metaObject = iListView->metaObject();
|
||||||
iCenterMode = value;
|
if (metaObject) {
|
||||||
HDEBUG("Center =" << iCenterMode);
|
int index = metaObject->indexOfEnumerator("PositionMode");
|
||||||
}
|
if (index >= 0) {
|
||||||
|
QMetaEnum metaEnum = metaObject->enumerator(index);
|
||||||
|
int value = metaEnum.keyToValue("Center", &ok);
|
||||||
|
if (ok) {
|
||||||
|
iCenterMode = value;
|
||||||
|
HDEBUG("Center =" << iCenterMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HASSERT(ok);
|
|
||||||
if (!ok) {
|
|
||||||
// This is what it normally is
|
|
||||||
iCenterMode = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
iPositionIsChanging = true;
|
HASSERT(ok);
|
||||||
positionViewAtIndex(aIndex, iCenterMode);
|
if (!ok) {
|
||||||
if (iCanRetry) {
|
// This is what it normally is
|
||||||
// This is probably a bug in QQuickListView - it first calculates
|
iCenterMode = 1;
|
||||||
// the item position and then starts instantiating the delegates.
|
|
||||||
// The very first time the item position always turns out to be
|
|
||||||
// zero because the average item size isn't known yet. So if we
|
|
||||||
// are trying to position the list at a non-zero index and instead
|
|
||||||
// we got positioned at zero, try it again. It doesn't make sense
|
|
||||||
// to retry more than once though.
|
|
||||||
if (aIndex > 0 && getCurrentIndex() == 0) {
|
|
||||||
// Didn't work from the first try, give it another go
|
|
||||||
HDEBUG("retrying...");
|
|
||||||
positionViewAtIndex(aIndex, iCenterMode);
|
|
||||||
}
|
|
||||||
iCanRetry = false;
|
|
||||||
}
|
}
|
||||||
iPositionIsChanging = false;
|
|
||||||
updateCurrentIndex();
|
|
||||||
}
|
}
|
||||||
|
iPositionIsChanging = true;
|
||||||
|
positionViewAtIndex(aIndex, iCenterMode);
|
||||||
|
// This is probably a bug in QQuickListView - it first calculates
|
||||||
|
// the item position and then starts instantiating the delegates.
|
||||||
|
// If there are no delegates yet, then the average item size is zero
|
||||||
|
// and the resulting item position will always turn out to be zero.
|
||||||
|
// So if we are trying to position the list at a non-zero index and
|
||||||
|
// instead we got positioned at zero, try it again.
|
||||||
|
if (aIndex > 0 && getCurrentIndex() == 0) {
|
||||||
|
// Didn't work from the first try, give it another go
|
||||||
|
HDEBUG("retrying...");
|
||||||
|
positionViewAtIndex(aIndex, iCenterMode);
|
||||||
|
}
|
||||||
|
iPositionIsChanging = false;
|
||||||
|
updateCurrentIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooksListWatcher::positionViewAtIndex(int aIndex, int aMode)
|
void BooksListWatcher::positionViewAtIndex(int aIndex, int aMode)
|
||||||
|
@ -181,6 +182,16 @@ qreal BooksListWatcher::contentY()
|
||||||
return getRealProperty(LISTVIEW_CONTENT_Y);
|
return getRealProperty(LISTVIEW_CONTENT_Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal BooksListWatcher::contentWidth()
|
||||||
|
{
|
||||||
|
return getRealProperty(LISTVIEW_CONTENT_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal BooksListWatcher::contentHeight()
|
||||||
|
{
|
||||||
|
return getRealProperty(LISTVIEW_CONTENT_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
int BooksListWatcher::getCurrentIndex()
|
int BooksListWatcher::getCurrentIndex()
|
||||||
{
|
{
|
||||||
if (iListView) {
|
if (iListView) {
|
||||||
|
@ -194,13 +205,29 @@ int BooksListWatcher::getCurrentIndex()
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooksListWatcher::updateCurrentIndex()
|
void BooksListWatcher::tryToRestoreCurrentIndex()
|
||||||
{
|
{
|
||||||
|
HASSERT(!iPositionIsChanging);
|
||||||
const int index = getCurrentIndex();
|
const int index = getCurrentIndex();
|
||||||
if (iCurrentIndex != index) {
|
if (iCurrentIndex != index) {
|
||||||
HDEBUG(index);
|
if (iCurrentIndex >= 0) {
|
||||||
iCurrentIndex = index;
|
doPositionViewAtIndex(iCurrentIndex);
|
||||||
Q_EMIT currentIndexChanged();
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksListWatcher::updateCurrentIndex()
|
||||||
|
{
|
||||||
|
HASSERT(!iPositionIsChanging);
|
||||||
|
if (contentWidth() > 0 || contentHeight() > 0) {
|
||||||
|
const int index = getCurrentIndex();
|
||||||
|
if (iCurrentIndex != index) {
|
||||||
|
iCurrentIndex = index;
|
||||||
|
HDEBUG(index << contentWidth() << "x" << contentHeight());
|
||||||
|
Q_EMIT currentIndexChanged();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HDEBUG(contentWidth() << "x" << contentHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,6 +238,7 @@ void BooksListWatcher::updateSize()
|
||||||
if (iSize != size) {
|
if (iSize != size) {
|
||||||
const QSize oldSize(iSize);
|
const QSize oldSize(iSize);
|
||||||
iSize = size;
|
iSize = size;
|
||||||
|
tryToRestoreCurrentIndex();
|
||||||
Q_EMIT sizeChanged();
|
Q_EMIT sizeChanged();
|
||||||
if (oldSize.width() != iSize.width()) {
|
if (oldSize.width() != iSize.width()) {
|
||||||
Q_EMIT widthChanged();
|
Q_EMIT widthChanged();
|
||||||
|
@ -272,6 +300,7 @@ void BooksListWatcher::onContentSizeChanged()
|
||||||
{
|
{
|
||||||
HASSERT(sender() == iListView);
|
HASSERT(sender() == iListView);
|
||||||
if (!iPositionIsChanging) {
|
if (!iPositionIsChanging) {
|
||||||
|
tryToRestoreCurrentIndex();
|
||||||
updateCurrentIndex();
|
updateCurrentIndex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -64,10 +64,14 @@ public:
|
||||||
private:
|
private:
|
||||||
qreal contentX();
|
qreal contentX();
|
||||||
qreal contentY();
|
qreal contentY();
|
||||||
|
qreal contentWidth();
|
||||||
|
qreal contentHeight();
|
||||||
qreal getRealProperty(const char *name, qreal defaultValue = 0.0);
|
qreal getRealProperty(const char *name, qreal defaultValue = 0.0);
|
||||||
int getCurrentIndex();
|
int getCurrentIndex();
|
||||||
|
void doPositionViewAtIndex(int aIndex);
|
||||||
void positionViewAtIndex(int aIndex, int aMode);
|
void positionViewAtIndex(int aIndex, int aMode);
|
||||||
void updateCurrentIndex();
|
void updateCurrentIndex();
|
||||||
|
void tryToRestoreCurrentIndex();
|
||||||
void updateSize();
|
void updateSize();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
|
@ -93,7 +97,6 @@ private:
|
||||||
QQuickItem* iListView;
|
QQuickItem* iListView;
|
||||||
int iCenterMode;
|
int iCenterMode;
|
||||||
bool iPositionIsChanging;
|
bool iPositionIsChanging;
|
||||||
bool iCanRetry;
|
|
||||||
QTimer* iResizeTimer;
|
QTimer* iResizeTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
633
app/src/BooksPageStack.cpp
Normal file
633
app/src/BooksPageStack.cpp
Normal file
|
@ -0,0 +1,633 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||||
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
|
*
|
||||||
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BooksPageStack.h"
|
||||||
|
|
||||||
|
#include "HarbourDebug.h"
|
||||||
|
|
||||||
|
#define SignalModelChanged (1 << 0)
|
||||||
|
#define SignalCountChanged (1 << 1)
|
||||||
|
#define SignalCurrentIndexChanged (1 << 2)
|
||||||
|
#define SignalCurrentPageChanged (1 << 3)
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// BooksPageStack::Entry
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
class BooksPageStack::Entry {
|
||||||
|
public:
|
||||||
|
BooksPos iPos;
|
||||||
|
int iPage;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Entry() : iPos(0, 0, 0), iPage(0) {}
|
||||||
|
Entry(const BooksPos& aPos, int aPage) : iPos(aPos), iPage(aPage) {}
|
||||||
|
Entry(const Entry& aEntry) : iPos(aEntry.iPos), iPage(aEntry.iPage) {}
|
||||||
|
|
||||||
|
const Entry& operator = (const Entry& Entry)
|
||||||
|
{
|
||||||
|
iPage = Entry.iPage;
|
||||||
|
iPos = Entry.iPos;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator == (const Entry& aEntry) const
|
||||||
|
{
|
||||||
|
return iPage == aEntry.iPage && iPos == aEntry.iPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator != (const Entry& aEntry) const
|
||||||
|
{
|
||||||
|
return iPage != aEntry.iPage || iPos != aEntry.iPos;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// BooksPageStack::Private
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
class BooksPageStack::Private : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QList<Entry> iEntries;
|
||||||
|
int iCurrentIndex;
|
||||||
|
int iQueuedSignals;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAX_DEPTH = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
BooksPos::List iPageMarks;
|
||||||
|
BooksPageStack* iModel;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Private(BooksPageStack* aModel);
|
||||||
|
|
||||||
|
BooksPos::Stack getStack() const;
|
||||||
|
bool isValidIndex(int aIndex) const;
|
||||||
|
void setCurrentIndex(int aIndex);
|
||||||
|
int currentPage() const;
|
||||||
|
int pageAt(int aIndex) const;
|
||||||
|
void setCurrentPage(int aPage);
|
||||||
|
void setPageAt(int aIndex, int aPage);
|
||||||
|
void setStack(BooksPos::List aStack, int aCurrentPos);
|
||||||
|
void setPageMarks(BooksPos::List aPageMarks);
|
||||||
|
void push(BooksPos aPos, int aPage);
|
||||||
|
void push(BooksPos);
|
||||||
|
void push(int aPage);
|
||||||
|
void pop();
|
||||||
|
void clear();
|
||||||
|
void emitQueuedSignals();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onModelChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BooksPos getPosAt(int aIndex) const;
|
||||||
|
int findPage(BooksPos aPos) const;
|
||||||
|
int makeIndexValid(int aIndex) const;
|
||||||
|
void pageChanged(int aIndex);
|
||||||
|
void checkCurrentIndex(int aLastIndex);
|
||||||
|
void checkCurrentPage(int aLastCurrentPage);
|
||||||
|
void checkCount(int aLastCount);
|
||||||
|
int validateCurrentIndex();
|
||||||
|
void queueSignals(int aSignals);
|
||||||
|
};
|
||||||
|
|
||||||
|
BooksPageStack::Private::Private(BooksPageStack* aModel) :
|
||||||
|
QObject(aModel),
|
||||||
|
iCurrentIndex(0),
|
||||||
|
iQueuedSignals(0),
|
||||||
|
iModel(aModel)
|
||||||
|
{
|
||||||
|
iEntries.append(Entry());
|
||||||
|
connect(aModel,
|
||||||
|
SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
|
||||||
|
SLOT(onModelChanged()));
|
||||||
|
connect(aModel,
|
||||||
|
SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||||
|
SLOT(onModelChanged()));
|
||||||
|
connect(aModel,
|
||||||
|
SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||||||
|
SLOT(onModelChanged()));
|
||||||
|
connect(aModel,
|
||||||
|
SIGNAL(modelReset()),
|
||||||
|
SLOT(onModelChanged()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::emitQueuedSignals()
|
||||||
|
{
|
||||||
|
static const struct SignalInfo {
|
||||||
|
int signal;
|
||||||
|
void (BooksPageStack::*fn)();
|
||||||
|
} signalInfo [] = {
|
||||||
|
{ SignalModelChanged, &BooksPageStack::changed },
|
||||||
|
{ SignalCountChanged, &BooksPageStack::countChanged },
|
||||||
|
{ SignalCurrentIndexChanged, &BooksPageStack::currentIndexChanged },
|
||||||
|
{ SignalCurrentPageChanged, &BooksPageStack::currentPageChanged}
|
||||||
|
};
|
||||||
|
const uint n = sizeof(signalInfo)/sizeof(signalInfo[0]);
|
||||||
|
for (uint i=0; i<n && iQueuedSignals; i++) {
|
||||||
|
if (iQueuedSignals & signalInfo[i].signal) {
|
||||||
|
iQueuedSignals &= ~signalInfo[i].signal;
|
||||||
|
Q_EMIT (iModel->*(signalInfo[i].fn))();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::onModelChanged()
|
||||||
|
{
|
||||||
|
queueSignals(SignalModelChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BooksPageStack::Private::queueSignals(int aSignals)
|
||||||
|
{
|
||||||
|
iQueuedSignals |= aSignals;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BooksPageStack::Private::makeIndexValid(int aIndex) const
|
||||||
|
{
|
||||||
|
if (aIndex < 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (aIndex >= iEntries.count()) {
|
||||||
|
return iEntries.count() - 1;
|
||||||
|
}
|
||||||
|
return aIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool BooksPageStack::Private::isValidIndex(int aIndex) const
|
||||||
|
{
|
||||||
|
return aIndex >= 0 && aIndex < iEntries.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BooksPageStack::Private::checkCurrentIndex(int aLastIndex)
|
||||||
|
{
|
||||||
|
if (validateCurrentIndex() != aLastIndex) {
|
||||||
|
queueSignals(SignalCurrentIndexChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BooksPageStack::Private::checkCurrentPage(int aLastCurrentPage)
|
||||||
|
{
|
||||||
|
if (currentPage() != aLastCurrentPage) {
|
||||||
|
queueSignals(SignalCurrentPageChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BooksPageStack::Private::checkCount(int aLastCount)
|
||||||
|
{
|
||||||
|
if (iEntries.count() != aLastCount) {
|
||||||
|
queueSignals(SignalCountChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int BooksPageStack::Private::validateCurrentIndex()
|
||||||
|
{
|
||||||
|
const int validIndex = makeIndexValid(iCurrentIndex);
|
||||||
|
if (iCurrentIndex != validIndex) {
|
||||||
|
iCurrentIndex = validIndex;
|
||||||
|
queueSignals(SignalCurrentIndexChanged);
|
||||||
|
}
|
||||||
|
return iCurrentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int BooksPageStack::Private::currentPage() const
|
||||||
|
{
|
||||||
|
return iEntries.at(iCurrentIndex).iPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BooksPageStack::Private::pageAt(int aIndex) const
|
||||||
|
{
|
||||||
|
if (isValidIndex(aIndex)) {
|
||||||
|
return iEntries.at(aIndex).iPage;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::setCurrentIndex(int aIndex)
|
||||||
|
{
|
||||||
|
const int newIndex = makeIndexValid(aIndex);
|
||||||
|
if (iCurrentIndex != newIndex) {
|
||||||
|
const int oldCurrentPage = currentPage();
|
||||||
|
iCurrentIndex = newIndex;
|
||||||
|
HDEBUG(iCurrentIndex);
|
||||||
|
checkCurrentPage(oldCurrentPage);
|
||||||
|
queueSignals(SignalCurrentIndexChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::setPageAt(int aIndex, int aPage)
|
||||||
|
{
|
||||||
|
Entry entry = iEntries.at(aIndex);
|
||||||
|
if (entry.iPage != aPage) {
|
||||||
|
entry.iPage = aPage;
|
||||||
|
const int np = iPageMarks.count();
|
||||||
|
if (np > 0) {
|
||||||
|
entry.iPos = (aPage < 0) ? iPageMarks.at(0) :
|
||||||
|
(aPage >= np) ? iPageMarks.at(np-1) :
|
||||||
|
iPageMarks.at(aPage);
|
||||||
|
} else {
|
||||||
|
entry.iPos.set(0, 0, 0);
|
||||||
|
}
|
||||||
|
iEntries[aIndex] = entry;
|
||||||
|
pageChanged(aIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BooksPageStack::Private::setCurrentPage(int aPage)
|
||||||
|
{
|
||||||
|
setPageAt(iCurrentIndex, aPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::pageChanged(int aIndex)
|
||||||
|
{
|
||||||
|
QVector<int> roles;
|
||||||
|
roles.append(PageRole);
|
||||||
|
QModelIndex modelIndex(iModel->createIndex(aIndex, 0));
|
||||||
|
Q_EMIT iModel->dataChanged(modelIndex, modelIndex, roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::setStack(BooksPos::List aStack, int aStackPos)
|
||||||
|
{
|
||||||
|
if (aStack.isEmpty()) {
|
||||||
|
aStack = BooksPos::List();
|
||||||
|
aStack.append(BooksPos(0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// First entry (always exists)
|
||||||
|
BooksPos pos = aStack.at(0);
|
||||||
|
Entry lastEntry(pos, findPage(pos));
|
||||||
|
if (iEntries.at(0) != lastEntry) {
|
||||||
|
iEntries[0] = lastEntry;
|
||||||
|
pageChanged(0);
|
||||||
|
} else {
|
||||||
|
iEntries[0] = lastEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update other entries
|
||||||
|
int entryIndex = 1, stackIndex = 1;
|
||||||
|
const int oldEntryCount = iEntries.count();
|
||||||
|
while (entryIndex < oldEntryCount && stackIndex < aStack.count()) {
|
||||||
|
pos = aStack.at(stackIndex++);
|
||||||
|
Entry entry(pos, findPage(pos));
|
||||||
|
if (iEntries.at(entryIndex) != entry) {
|
||||||
|
iEntries[entryIndex] = entry;
|
||||||
|
pageChanged(entryIndex);
|
||||||
|
} else {
|
||||||
|
iEntries[entryIndex] = entry;
|
||||||
|
}
|
||||||
|
lastEntry = entry;
|
||||||
|
entryIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entryIndex < oldEntryCount) {
|
||||||
|
// We have run out of stack entries, remove remainig rows
|
||||||
|
iModel->beginRemoveRows(QModelIndex(), entryIndex, oldEntryCount-1);
|
||||||
|
while (iEntries.count() > entryIndex) {
|
||||||
|
iEntries.removeLast();
|
||||||
|
}
|
||||||
|
iModel->endRemoveRows();
|
||||||
|
Q_EMIT iModel->countChanged();
|
||||||
|
} else {
|
||||||
|
// Add new entries if necessary
|
||||||
|
while (stackIndex < aStack.count()) {
|
||||||
|
pos = aStack.at(stackIndex++);
|
||||||
|
Entry entry(pos, findPage(pos));
|
||||||
|
if (entry != lastEntry) {
|
||||||
|
iEntries.append(entry);
|
||||||
|
lastEntry = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int n = iEntries.count();
|
||||||
|
if (n > oldEntryCount) {
|
||||||
|
// We have added some entries, update the model
|
||||||
|
iModel->beginInsertRows(QModelIndex(), oldEntryCount, n-1);
|
||||||
|
iModel->endInsertRows();
|
||||||
|
Q_EMIT iModel->countChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentIndex(aStackPos);
|
||||||
|
validateCurrentIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::setPageMarks(BooksPos::List aPageMarks)
|
||||||
|
{
|
||||||
|
if (iPageMarks != aPageMarks) {
|
||||||
|
iPageMarks = aPageMarks;
|
||||||
|
const int prevCurrentPage = currentPage();
|
||||||
|
HDEBUG(iPageMarks);
|
||||||
|
const int n = iEntries.count();
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
Entry entry = iEntries.at(i);
|
||||||
|
const int page = findPage(entry.iPos);
|
||||||
|
if (entry.iPage != page) {
|
||||||
|
entry.iPage = page;
|
||||||
|
iEntries[i] = entry;
|
||||||
|
pageChanged(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkCurrentPage(prevCurrentPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int BooksPageStack::Private::findPage(BooksPos aPos) const
|
||||||
|
{
|
||||||
|
BooksPos::ConstIterator it = qBinaryFind(iPageMarks, aPos);
|
||||||
|
if (it == iPageMarks.end()) {
|
||||||
|
it = qLowerBound(iPageMarks, aPos);
|
||||||
|
if (it == iPageMarks.end()) {
|
||||||
|
return iPageMarks.count() - 1;
|
||||||
|
} else if (it == iPageMarks.begin()) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return (it - iPageMarks.begin()) - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return it - iPageMarks.begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BooksPos BooksPageStack::Private::getPosAt(int aIndex) const
|
||||||
|
{
|
||||||
|
if (iPageMarks.isEmpty()) {
|
||||||
|
return BooksPos(0, 0, 0);
|
||||||
|
} else if (aIndex < 0) {
|
||||||
|
return iPageMarks.first();
|
||||||
|
} else if (aIndex >= iPageMarks.count()) {
|
||||||
|
return iPageMarks.last();
|
||||||
|
} else {
|
||||||
|
return iPageMarks.at(aIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::push(BooksPos aPos, int aPage)
|
||||||
|
{
|
||||||
|
Entry last = iEntries.last();
|
||||||
|
if (last.iPos != aPos || last.iPage != aPage) {
|
||||||
|
// We push on top of the current position. If we have reached
|
||||||
|
// the depth limit, we push the entire stack down
|
||||||
|
const int n = iEntries.count();
|
||||||
|
if (n >= MAX_DEPTH) {
|
||||||
|
for (int i=1; i<n; i++) {
|
||||||
|
iEntries[i-1] = iEntries[i];
|
||||||
|
pageChanged(i-1);
|
||||||
|
}
|
||||||
|
iEntries[n-1] = Entry(aPos, aPage);
|
||||||
|
pageChanged(n-1);
|
||||||
|
} else {
|
||||||
|
if (n >= iCurrentIndex+2) {
|
||||||
|
if (n > iCurrentIndex+2) {
|
||||||
|
// Drop unnecessary entries
|
||||||
|
iModel->beginRemoveRows(QModelIndex(), iCurrentIndex+2, n-1);
|
||||||
|
while (iEntries.count() > iCurrentIndex+2) {
|
||||||
|
iEntries.removeLast();
|
||||||
|
}
|
||||||
|
iModel->endRemoveRows();
|
||||||
|
Q_EMIT iModel->countChanged();
|
||||||
|
queueSignals(SignalCountChanged);
|
||||||
|
}
|
||||||
|
// And replace the next one
|
||||||
|
setPageAt(iCurrentIndex+1, aPage);
|
||||||
|
} else {
|
||||||
|
// Just push the new one
|
||||||
|
const int i = iCurrentIndex+1;
|
||||||
|
iModel->beginInsertRows(QModelIndex(), i, i);
|
||||||
|
iEntries.append(Entry(aPos, aPage));
|
||||||
|
iModel->endInsertRows();
|
||||||
|
queueSignals(SignalCountChanged);
|
||||||
|
}
|
||||||
|
// Move the current index
|
||||||
|
setCurrentIndex(iCurrentIndex+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::push(BooksPos aPos)
|
||||||
|
{
|
||||||
|
if (iEntries.last().iPos != aPos) {
|
||||||
|
push(aPos, findPage(aPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::push(int aPage)
|
||||||
|
{
|
||||||
|
if (iEntries.last().iPage != aPage) {
|
||||||
|
push(getPosAt(aPage), aPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::pop()
|
||||||
|
{
|
||||||
|
const int n = iEntries.count();
|
||||||
|
if (n > 1) {
|
||||||
|
iModel->beginRemoveRows(QModelIndex(), n-1, n-1);
|
||||||
|
iEntries.removeLast();
|
||||||
|
validateCurrentIndex();
|
||||||
|
iModel->endRemoveRows();
|
||||||
|
queueSignals(SignalCountChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::Private::clear()
|
||||||
|
{
|
||||||
|
const int n = iEntries.count();
|
||||||
|
if (n > 1) {
|
||||||
|
Entry currentEntry = iEntries.at(iCurrentIndex);
|
||||||
|
iModel->beginRemoveRows(QModelIndex(), 1, n-1);
|
||||||
|
while (iEntries.count() > 1) {
|
||||||
|
iEntries.removeLast();
|
||||||
|
}
|
||||||
|
validateCurrentIndex();
|
||||||
|
iModel->endRemoveRows();
|
||||||
|
if (iEntries.at(0) != currentEntry) {
|
||||||
|
iEntries[0] = currentEntry;
|
||||||
|
pageChanged(0);
|
||||||
|
}
|
||||||
|
queueSignals(SignalCountChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BooksPos::Stack BooksPageStack::Private::getStack() const
|
||||||
|
{
|
||||||
|
const int n = iEntries.count();
|
||||||
|
BooksPos::Stack stack;
|
||||||
|
stack.iList.reserve(n);
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
stack.iList.append(iEntries.at(i).iPos);
|
||||||
|
}
|
||||||
|
stack.iPos = iCurrentIndex;
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// BooksPageStack
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
BooksPageStack::BooksPageStack(QObject* aParent) :
|
||||||
|
QAbstractListModel(aParent),
|
||||||
|
iPrivate(new Private(this))
|
||||||
|
{
|
||||||
|
#if QT_VERSION < 0x050000
|
||||||
|
setRoleNames(roleNames());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int BooksPageStack::count() const
|
||||||
|
{
|
||||||
|
return iPrivate->iEntries.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
int BooksPageStack::currentIndex() const
|
||||||
|
{
|
||||||
|
return iPrivate->iCurrentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BooksPageStack::currentPage() const
|
||||||
|
{
|
||||||
|
return iPrivate->currentPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::setCurrentIndex(int aIndex)
|
||||||
|
{
|
||||||
|
iPrivate->setCurrentIndex(aIndex);
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::setCurrentPage(int aPage)
|
||||||
|
{
|
||||||
|
iPrivate->setCurrentPage(aPage);
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::back()
|
||||||
|
{
|
||||||
|
iPrivate->setCurrentIndex(iPrivate->iCurrentIndex - 1);
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::forward()
|
||||||
|
{
|
||||||
|
iPrivate->setCurrentIndex(iPrivate->iCurrentIndex + 1);
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
BooksPos::Stack BooksPageStack::getStack() const
|
||||||
|
{
|
||||||
|
return iPrivate->getStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::setStack(BooksPos::List aStack, int aCurrentPos)
|
||||||
|
{
|
||||||
|
iPrivate->setStack(aStack, aCurrentPos);
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::setPageMarks(BooksPos::List aPageMarks)
|
||||||
|
{
|
||||||
|
iPrivate->setPageMarks(aPageMarks);
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
int BooksPageStack::pageAt(int aIndex)
|
||||||
|
{
|
||||||
|
return iPrivate->pageAt(aIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::pushPage(int aPage)
|
||||||
|
{
|
||||||
|
HDEBUG(aPage);
|
||||||
|
iPrivate->push(aPage);
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::pushPosition(BooksPos aPos)
|
||||||
|
{
|
||||||
|
HDEBUG("" << aPos);
|
||||||
|
iPrivate->push(aPos);
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::pop()
|
||||||
|
{
|
||||||
|
HDEBUG("");
|
||||||
|
iPrivate->pop();
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooksPageStack::clear()
|
||||||
|
{
|
||||||
|
HDEBUG("");
|
||||||
|
iPrivate->clear();
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int,QByteArray> BooksPageStack::roleNames() const
|
||||||
|
{
|
||||||
|
QHash<int, QByteArray> roles;
|
||||||
|
roles.insert(PageRole, "page");
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BooksPageStack::rowCount(const QModelIndex&) const
|
||||||
|
{
|
||||||
|
return iPrivate->iEntries.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant BooksPageStack::data(const QModelIndex& aIndex, int aRole) const
|
||||||
|
{
|
||||||
|
const int row = aIndex.row();
|
||||||
|
if (iPrivate->isValidIndex(row) && aRole == PageRole) {
|
||||||
|
return iPrivate->iEntries.at(row).iPage;
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BooksPageStack::setData(const QModelIndex& aIndex, const QVariant& aValue,
|
||||||
|
int aRole)
|
||||||
|
{
|
||||||
|
const int row = aIndex.row();
|
||||||
|
if (iPrivate->isValidIndex(row) && aRole == PageRole) {
|
||||||
|
bool ok = false;
|
||||||
|
const int page = aValue.toInt(&ok);
|
||||||
|
if (page >= 0 && ok) {
|
||||||
|
iPrivate->setPageAt(row, page);
|
||||||
|
iPrivate->emitQueuedSignals();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "BooksPageStack.moc"
|
97
app/src/BooksPageStack.h
Normal file
97
app/src/BooksPageStack.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2017 Jolla Ltd.
|
||||||
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
|
*
|
||||||
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Jolla Ltd nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOKS_STACK_MODEL_H
|
||||||
|
#define BOOKS_STACK_MODEL_H
|
||||||
|
|
||||||
|
#include "BooksTypes.h"
|
||||||
|
#include "BooksPos.h"
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QtQml>
|
||||||
|
|
||||||
|
class BooksPageStack: public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||||
|
Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged)
|
||||||
|
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
|
||||||
|
|
||||||
|
enum Role {
|
||||||
|
PageRole = Qt::UserRole // "page"
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BooksPageStack(QObject* aParent = NULL);
|
||||||
|
|
||||||
|
int count() const;
|
||||||
|
|
||||||
|
int currentIndex() const;
|
||||||
|
void setCurrentIndex(int aIndex);
|
||||||
|
|
||||||
|
int currentPage() const;
|
||||||
|
void setCurrentPage(int aPage);
|
||||||
|
|
||||||
|
BooksPos::Stack getStack() const;
|
||||||
|
void setStack(BooksPos::List aStack, int aCurrentPos);
|
||||||
|
void setPageMarks(BooksPos::List aPageMarks);
|
||||||
|
|
||||||
|
// QAbstractListModel
|
||||||
|
QHash<int,QByteArray> roleNames() const;
|
||||||
|
int rowCount(const QModelIndex& aParent) const;
|
||||||
|
QVariant data(const QModelIndex& aIndex, int aRole) const;
|
||||||
|
bool setData(const QModelIndex& aIndex, const QVariant& aValue, int aRole);
|
||||||
|
|
||||||
|
Q_INVOKABLE int pageAt(int aIndex);
|
||||||
|
Q_INVOKABLE void pushPage(int aPage);
|
||||||
|
Q_INVOKABLE void pushPosition(BooksPos aPos);
|
||||||
|
Q_INVOKABLE void pop();
|
||||||
|
Q_INVOKABLE void clear();
|
||||||
|
Q_INVOKABLE void back();
|
||||||
|
Q_INVOKABLE void forward();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void changed();
|
||||||
|
void countChanged();
|
||||||
|
void currentIndexChanged();
|
||||||
|
void currentPageChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Entry;
|
||||||
|
class Private;
|
||||||
|
Private* iPrivate;
|
||||||
|
};
|
||||||
|
|
||||||
|
QML_DECLARE_TYPE(BooksPageStack)
|
||||||
|
|
||||||
|
#endif // BOOKS_STACK_MODEL_H
|
|
@ -723,10 +723,10 @@ void BooksPageWidget::onLongPressTaskDone()
|
||||||
}
|
}
|
||||||
} else if (task->iKind == INTERNAL_HYPERLINK) {
|
} else if (task->iKind == INTERNAL_HYPERLINK) {
|
||||||
if (iModel) {
|
if (iModel) {
|
||||||
int page = iModel->linkToPage(task->iLink);
|
BooksPos pos = iModel->linkPosition(task->iLink);
|
||||||
if (page >= 0) {
|
if (pos.valid()) {
|
||||||
HDEBUG("link to page" << page);
|
HDEBUG("link to" << pos);
|
||||||
Q_EMIT jumpToPage(page);
|
Q_EMIT pushPosition(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (task->iKind == FOOTNOTE) {
|
} else if (task->iKind == FOOTNOTE) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -101,6 +101,7 @@ Q_SIGNALS:
|
||||||
void activeTouch(int touchX, int touchY);
|
void activeTouch(int touchX, int touchY);
|
||||||
void jumpToPage(int page);
|
void jumpToPage(int page);
|
||||||
void showFootnote(int touchX, int touchY, QString text, QString imageId);
|
void showFootnote(int touchX, int touchY, QString text, QString imageId);
|
||||||
|
void pushPosition(BooksPos position);
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onWidthChanged();
|
void onWidthChanged();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
#ifndef BOOKS_POSITION_H
|
#ifndef BOOKS_POSITION_H
|
||||||
#define BOOKS_POSITION_H
|
#define BOOKS_POSITION_H
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
@ -46,6 +47,7 @@ struct BooksPos {
|
||||||
typedef QList<BooksPos> List;
|
typedef QList<BooksPos> List;
|
||||||
typedef QList<BooksPos>::iterator Iterator;
|
typedef QList<BooksPos>::iterator Iterator;
|
||||||
typedef QList<BooksPos>::const_iterator ConstIterator;
|
typedef QList<BooksPos>::const_iterator ConstIterator;
|
||||||
|
struct Stack { List iList; int iPos; };
|
||||||
|
|
||||||
BooksPos() :
|
BooksPos() :
|
||||||
iParagraphIndex(-1),
|
iParagraphIndex(-1),
|
||||||
|
@ -80,6 +82,13 @@ struct BooksPos {
|
||||||
return iParagraphIndex >= 0 && iElementIndex >= 0 && iCharIndex >= 0;
|
return iParagraphIndex >= 0 && iElementIndex >= 0 && iCharIndex >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set(int aParagraphIndex, int aElementIndex, int aCharIndex)
|
||||||
|
{
|
||||||
|
iParagraphIndex = aParagraphIndex;
|
||||||
|
iElementIndex = aElementIndex;
|
||||||
|
iCharIndex = aCharIndex;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant toVariant() const
|
QVariant toVariant() const
|
||||||
{
|
{
|
||||||
QVariantList list;
|
QVariantList list;
|
||||||
|
@ -124,8 +133,7 @@ struct BooksPos {
|
||||||
(iParagraphIndex > aPos.iParagraphIndex) ? false :
|
(iParagraphIndex > aPos.iParagraphIndex) ? false :
|
||||||
(iElementIndex < aPos.iElementIndex) ? true :
|
(iElementIndex < aPos.iElementIndex) ? true :
|
||||||
(iElementIndex > aPos.iElementIndex) ? false :
|
(iElementIndex > aPos.iElementIndex) ? false :
|
||||||
(iCharIndex < aPos.iCharIndex) ? true :
|
(iCharIndex < aPos.iCharIndex);
|
||||||
(iCharIndex > aPos.iCharIndex) ? false : true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator > (const BooksPos& aPos) const
|
bool operator > (const BooksPos& aPos) const
|
||||||
|
@ -159,7 +167,7 @@ struct BooksPos {
|
||||||
|
|
||||||
QString toString() const
|
QString toString() const
|
||||||
{
|
{
|
||||||
return QString("BooksPos(%1,%2,%3)").arg(iParagraphIndex).
|
return QString("(%1,%2,%3)").arg(iParagraphIndex).
|
||||||
arg(iElementIndex).arg(iCharIndex);
|
arg(iElementIndex).arg(iCharIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,4 +181,6 @@ struct BooksPos {
|
||||||
inline QDebug& operator<<(QDebug& aDebug, const BooksPos& aPos)
|
inline QDebug& operator<<(QDebug& aDebug, const BooksPos& aPos)
|
||||||
{ aDebug << qPrintable(aPos.toString()); return aDebug; }
|
{ aDebug << qPrintable(aPos.toString()); return aDebug; }
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(BooksPos)
|
||||||
|
|
||||||
#endif /* BOOKS_POSITION_H */
|
#endif /* BOOKS_POSITION_H */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -1119,7 +1119,7 @@ void BooksShelf::onCopyTaskDone()
|
||||||
copy = task->iDestItem->book();
|
copy = task->iDestItem->book();
|
||||||
if (copy) {
|
if (copy) {
|
||||||
copy->retain();
|
copy->retain();
|
||||||
copy->setLastPos(src->lastPos());
|
copy->setPageStack(src->pageStack(), src->pageStackPos());
|
||||||
copy->setCoverImage(src->coverImage());
|
copy->setCoverImage(src->coverImage());
|
||||||
copy->requestCoverImage();
|
copy->requestCoverImage();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
* Copyright (C) 2015-2017 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of the BSD license as follows:
|
* You may use this file under the terms of the BSD license as follows:
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "BooksDefs.h"
|
#include "BooksDefs.h"
|
||||||
|
#include "BooksPos.h"
|
||||||
#include "BooksShelf.h"
|
#include "BooksShelf.h"
|
||||||
#include "BooksBook.h"
|
#include "BooksBook.h"
|
||||||
#include "BooksBookModel.h"
|
#include "BooksBookModel.h"
|
||||||
|
@ -39,6 +40,7 @@
|
||||||
#include "BooksConfig.h"
|
#include "BooksConfig.h"
|
||||||
#include "BooksImportModel.h"
|
#include "BooksImportModel.h"
|
||||||
#include "BooksPathModel.h"
|
#include "BooksPathModel.h"
|
||||||
|
#include "BooksPageStack.h"
|
||||||
#include "BooksStorageModel.h"
|
#include "BooksStorageModel.h"
|
||||||
#include "BooksPageWidget.h"
|
#include "BooksPageWidget.h"
|
||||||
#include "BooksListWatcher.h"
|
#include "BooksListWatcher.h"
|
||||||
|
@ -68,12 +70,14 @@
|
||||||
Q_DECL_EXPORT int main(int argc, char **argv)
|
Q_DECL_EXPORT int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
QGuiApplication* app = SailfishApp::application(argc, argv);
|
QGuiApplication* app = SailfishApp::application(argc, argv);
|
||||||
|
qRegisterMetaType<BooksPos>();
|
||||||
BOOKS_QML_REGISTER(BooksShelf, "Shelf");
|
BOOKS_QML_REGISTER(BooksShelf, "Shelf");
|
||||||
BOOKS_QML_REGISTER(BooksBook, "Book");
|
BOOKS_QML_REGISTER(BooksBook, "Book");
|
||||||
BOOKS_QML_REGISTER(BooksBookModel, "BookModel");
|
BOOKS_QML_REGISTER(BooksBookModel, "BookModel");
|
||||||
BOOKS_QML_REGISTER(BooksCoverModel, "CoverModel");
|
BOOKS_QML_REGISTER(BooksCoverModel, "CoverModel");
|
||||||
BOOKS_QML_REGISTER(BooksImportModel, "BooksImportModel");
|
BOOKS_QML_REGISTER(BooksImportModel, "BooksImportModel");
|
||||||
BOOKS_QML_REGISTER(BooksPathModel, "BooksPathModel");
|
BOOKS_QML_REGISTER(BooksPathModel, "BooksPathModel");
|
||||||
|
BOOKS_QML_REGISTER(BooksPageStack, "BooksPageStack");
|
||||||
BOOKS_QML_REGISTER(BooksStorageModel, "BookStorage");
|
BOOKS_QML_REGISTER(BooksStorageModel, "BookStorage");
|
||||||
BOOKS_QML_REGISTER(BooksPageWidget, "PageWidget");
|
BOOKS_QML_REGISTER(BooksPageWidget, "PageWidget");
|
||||||
BOOKS_QML_REGISTER(BooksListWatcher, "ListWatcher");
|
BOOKS_QML_REGISTER(BooksListWatcher, "ListWatcher");
|
||||||
|
|
Loading…
Reference in a new issue