Sailfish integration
This commit is contained in:
parent
9629f7bb46
commit
e9db1e773a
87 changed files with 12517 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
harbour-books.pro.user
|
||||
build
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -4,3 +4,6 @@
|
|||
[submodule "fbreader/upstream"]
|
||||
path = fbreader/upstream
|
||||
url = https://github.com/geometer/FBReader.git
|
||||
[submodule "harbour-lib"]
|
||||
path = harbour-lib
|
||||
url = https://github.com/monich/harbour-lib.git
|
||||
|
|
5
README.md
Normal file
5
README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
## E-book reader for Sailfish OS
|
||||
|
||||
![icon](app/harbour-books.png)
|
||||
|
||||
The core functionality is based on [FBReader](https://github.com/geometer/FBReader) source code with very few modifications. Books are imported from the Downloads folder, where they are saved by the browser or email client. Alternatively, you can manually copy your books to the Books directory under the home folder. Removable storage is supported as well. In theory, it should be able to handle all E-book formats supported by FBReader. Tested mostly with epub and fb2.
|
138
app/app.pro
Normal file
138
app/app.pro
Normal file
|
@ -0,0 +1,138 @@
|
|||
TARGET = harbour-books
|
||||
CONFIG += sailfishapp link_pkgconfig
|
||||
PKGCONFIG += sailfishapp mlite5 expat glib-2.0
|
||||
#QT += dbus
|
||||
|
||||
!include(../common.pri)
|
||||
|
||||
CONFIG(debug, debug|release) {
|
||||
DEFINES += HARBOUR_DEBUG=1
|
||||
}
|
||||
|
||||
# Directories
|
||||
FBREADER_DIR = $$_PRO_FILE_PWD_/../fbreader
|
||||
FRIBIDI_DIR = $$_PRO_FILE_PWD_/../fribidi
|
||||
LINEBREAK_DIR = $$_PRO_FILE_PWD_/../linebreak
|
||||
HARBOUR_LIB_DIR = $$_PRO_FILE_PWD_/../harbour-lib
|
||||
|
||||
# Libraries
|
||||
FBREADER_LIB = $$OUT_PWD/../fbreader/libfbreader.a
|
||||
FRIBIDI_LIB = $$OUT_PWD/../fribidi/libfribidi.a
|
||||
LINEBREAK_LIB = $$OUT_PWD/../linebreak/liblinebreak.a
|
||||
HARBOUR_LIB = $$OUT_PWD/../harbour-lib/libharbour-lib.a
|
||||
|
||||
PRE_TARGETDEPS += \
|
||||
$$FBREADER_LIB \
|
||||
$$FRIBIDI_LIB \
|
||||
$$LINEBREAK_LIB \
|
||||
$$HARBOUR_LIB
|
||||
LIBS += \
|
||||
$$FBREADER_LIB \
|
||||
$$FRIBIDI_LIB \
|
||||
$$LINEBREAK_LIB \
|
||||
$$HARBOUR_LIB \
|
||||
-lbz2 -lz -ldl
|
||||
|
||||
OTHER_FILES += \
|
||||
harbour-books.png \
|
||||
harbour-books.desktop \
|
||||
qml/*.qml \
|
||||
qml/images/* \
|
||||
data/default/* \
|
||||
data/zlibrary/core/encodings/* \
|
||||
data/zlibrary/core/resources/* \
|
||||
translations/*.ts
|
||||
|
||||
TARGET_DATA_DIR = /usr/share/harbour-books
|
||||
TARGET_DEFAULT_DATA_DIR = $$TARGET_DATA_DIR/data
|
||||
TARGET_ZLIBRARY_DATA_DIR = $$TARGET_DEFAULT_DATA_DIR
|
||||
|
||||
core_data.files = \
|
||||
data/zlibrary/core/*.gz \
|
||||
data/zlibrary/core/*.zip \
|
||||
data/zlibrary/core/encodings \
|
||||
data/zlibrary/core/resources
|
||||
core_data.path = $$TARGET_ZLIBRARY_DATA_DIR
|
||||
INSTALLS += core_data
|
||||
|
||||
text_data.files = data/zlibrary/text/*.zip
|
||||
text_data.path = $$TARGET_ZLIBRARY_DATA_DIR
|
||||
INSTALLS += text_data
|
||||
|
||||
defaults.files = data/default/*
|
||||
defaults.path = $$TARGET_ZLIBRARY_DATA_DIR
|
||||
INSTALLS += defaults
|
||||
|
||||
formats.files = data/formats/*
|
||||
formats.path = $$TARGET_DEFAULT_DATA_DIR/formats
|
||||
INSTALLS += formats
|
||||
|
||||
CONFIG += sailfishapp_i18n sailfishapp_i18n_idbased
|
||||
TRANSLATIONS += \
|
||||
translations/harbour-books.ts \
|
||||
translations/harbour-books-ru.ts
|
||||
|
||||
INCLUDEPATH += \
|
||||
src \
|
||||
$$HARBOUR_LIB_DIR/include \
|
||||
$$FBREADER_DIR/fbreader/fbreader/src \
|
||||
$$FBREADER_DIR/fbreader/zlibrary/text/include \
|
||||
$$FBREADER_DIR/fbreader/zlibrary/core/include \
|
||||
$$FBREADER_DIR/fbreader/zlibrary/core/src/view \
|
||||
$$FBREADER_DIR/fbreader/zlibrary/core/src/dialogs \
|
||||
$$FBREADER_DIR/fbreader/zlibrary/core/src/application \
|
||||
$$FBREADER_DIR/fbreader/zlibrary/core/src/options \
|
||||
$$FBREADER_DIR/fbreader/zlibrary/core/src/unix \
|
||||
$$FBREADER_DIR/fbreader/zlibrary/ui/src/qt4
|
||||
|
||||
SOURCES += \
|
||||
src/BooksBook.cpp \
|
||||
src/BooksBookModel.cpp \
|
||||
src/BooksConfig.cpp \
|
||||
src/BooksCoverModel.cpp \
|
||||
src/BooksCoverWidget.cpp \
|
||||
src/BooksDialogManager.cpp \
|
||||
src/BooksImportModel.cpp \
|
||||
src/BooksListWatcher.cpp \
|
||||
src/BooksLoadingProperty.cpp \
|
||||
src/BooksPageWidget.cpp \
|
||||
src/BooksPaintContext.cpp \
|
||||
src/BooksSaveTimer.cpp \
|
||||
src/BooksSettings.cpp \
|
||||
src/BooksShelf.cpp \
|
||||
src/BooksStorage.cpp \
|
||||
src/BooksStorageModel.cpp \
|
||||
src/BooksTask.cpp \
|
||||
src/BooksTextStyle.cpp \
|
||||
src/BooksTaskQueue.cpp \
|
||||
src/BooksTextView.cpp \
|
||||
src/libudev.c \
|
||||
src/main.cpp \
|
||||
src/ZLApplication.cpp \
|
||||
src/ZLibrary.cpp
|
||||
|
||||
HEADERS += \
|
||||
src/BooksBook.h \
|
||||
src/BooksBookModel.h \
|
||||
src/BooksConfig.h \
|
||||
src/BooksCoverModel.h \
|
||||
src/BooksCoverWidget.h \
|
||||
src/BooksDefs.h \
|
||||
src/BooksDialogManager.h \
|
||||
src/BooksImportModel.h \
|
||||
src/BooksItem.h \
|
||||
src/BooksListWatcher.h \
|
||||
src/BooksLoadingProperty.h \
|
||||
src/BooksPageWidget.h \
|
||||
src/BooksPaintContext.h \
|
||||
src/BooksPos.h \
|
||||
src/BooksSaveTimer.h \
|
||||
src/BooksSettings.h \
|
||||
src/BooksShelf.h \
|
||||
src/BooksStorage.h \
|
||||
src/BooksStorageModel.h \
|
||||
src/BooksTask.h \
|
||||
src/BooksTaskQueue.h \
|
||||
src/BooksTextView.h \
|
||||
src/BooksTextStyle.h \
|
||||
src/BooksTypes.h
|
1
app/data/default/styles.xml
Symbolic link
1
app/data/default/styles.xml
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../fbreader/fbreader/fbreader/data/default/styles.desktop.xml
|
1
app/data/formats
Symbolic link
1
app/data/formats
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../fbreader/fbreader/fbreader/data/formats
|
1
app/data/zlibrary/core
Symbolic link
1
app/data/zlibrary/core
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../fbreader/fbreader/zlibrary/core/data
|
1
app/data/zlibrary/text
Symbolic link
1
app/data/zlibrary/text
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../fbreader/fbreader/zlibrary/text/data
|
8
app/harbour-books.desktop
Normal file
8
app/harbour-books.desktop
Normal file
|
@ -0,0 +1,8 @@
|
|||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Books
|
||||
Name[ru]=Книги
|
||||
Comment=E-Book Reader
|
||||
Exec=harbour-books
|
||||
Icon=harbour-books
|
||||
X-Nemo-Application-Type=silica-qt5
|
BIN
app/harbour-books.png
Normal file
BIN
app/harbour-books.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
52
app/harbour-books.svg
Normal file
52
app/harbour-books.svg
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="86px"
|
||||
height="86px"
|
||||
viewBox="0 0 86 86"
|
||||
enable-background="new 0 0 86 86"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.48.2 r9819"><metadata
|
||||
id="metadata25"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata>
|
||||
<g
|
||||
id="Layer_1">
|
||||
<linearGradient
|
||||
id="SVGID_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="79.2383"
|
||||
y1="91.3279"
|
||||
x2="6.7619"
|
||||
y2="18.8514">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#f5d9a8;stop-opacity:1;"
|
||||
id="stop7" />
|
||||
<stop
|
||||
offset="0.99510002"
|
||||
style="stop-color:#cc9933;stop-opacity:1;"
|
||||
id="stop9" />
|
||||
</linearGradient>
|
||||
<path
|
||||
fill="url(#SVGID_1_)"
|
||||
d="M43,0.3C19.417,0.3,0.3,19.418,0.3,43c0,0.408,0,41.277,0,41.277c0,0.786,0.637,1.423,1.423,1.423 h82.553c0.786,0,1.423-0.637,1.423-1.423c0,0,0-40.908,0-41.277C85.7,19.418,66.583,0.3,43,0.3z"
|
||||
id="path11" />
|
||||
</g>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 65.244239,25.145325 2.755924,0 0,52.854675 -39.567187,0 C 22.625852,78 17.999837,73.964541 17.999837,67.960564 l 0,-45.768014 c 0,-3.248053 2.657498,-5.90555 5.905551,-5.90555 l 36.614411,0 0,45.374311 -32.086823,0 c -4.035459,0 -6.889809,2.165368 -6.889809,6.102402 l 0,0.196851 c 0,3.937034 2.85435,6.496106 6.889809,6.496106 l 36.811263,0 0,-49.311345 z m -4.72444,44.193201 -31.69312,0 c -0.885832,0 -1.673239,-0.492128 -1.673239,-1.476387 0,-0.787407 0.787407,-1.279537 1.673239,-1.279537 l 31.69312,0 0,2.755924 z"
|
||||
id="path4"
|
||||
style="fill:#cc0000;fill-opacity:1" /></svg>
|
After Width: | Height: | Size: 2.1 KiB |
253
app/qml/BooksBookView.qml
Normal file
253
app/qml/BooksBookView.qml
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
SilicaFlickable {
|
||||
id: root
|
||||
|
||||
property variant book
|
||||
property variant settings
|
||||
|
||||
signal closeBook()
|
||||
signal pageClicked(var page)
|
||||
|
||||
property int _currentPage: bookListWatcher.currentIndex
|
||||
property bool _loading: minLoadingDelay.running || !bookModel.pageCount
|
||||
property bool _pagerVisible: (_currentState.pager && book && bookModel.pageCount) ? 1 : 0
|
||||
property var _currentState: _visibilityStates[settings.pageDetails % _visibilityStates.length]
|
||||
readonly property var _visibilityStates: [
|
||||
{ pager: false, page: false, title: false, tools: false },
|
||||
{ pager: false, page: true, title: true, tools: false },
|
||||
{ pager: true, page: true, title: true, tools: true }
|
||||
]
|
||||
|
||||
PullDownMenu {
|
||||
MenuItem {
|
||||
id: defaultFontMenuItem
|
||||
//% "Use default fonts"
|
||||
text: qsTrId("book-font-default")
|
||||
enabled: settings.fontSize != Settings.DefaultFontSize
|
||||
onClicked: settings.fontSize = Settings.DefaultFontSize
|
||||
}
|
||||
MenuItem {
|
||||
id: smallerFontMenuItem
|
||||
//% "Use smaller fonts"
|
||||
text: qsTrId("book-font-smaller")
|
||||
enabled: settings.fontSize >= Settings.MinFontSize
|
||||
onClicked: settings.fontSize -= 1
|
||||
}
|
||||
MenuItem {
|
||||
id: largerFontMenuItem
|
||||
//% "Use larger fonts"
|
||||
text: qsTrId("book-font-larger")
|
||||
enabled: settings.fontSize <= Settings.MaxFontSize
|
||||
onClicked: settings.fontSize += 1
|
||||
}
|
||||
MenuItem {
|
||||
//% "Back to library"
|
||||
text: qsTrId("book-view-back")
|
||||
onClicked: root.closeBook()
|
||||
}
|
||||
|
||||
// Remove disabled items from the menu when we have a chance
|
||||
onActiveChanged: if (!active) hideDisabledItems()
|
||||
Component.onCompleted: hideDisabledItems()
|
||||
|
||||
function hideDisabledItems() {
|
||||
defaultFontMenuItem.visible = defaultFontMenuItem.enabled
|
||||
smallerFontMenuItem.visible = smallerFontMenuItem.enabled
|
||||
largerFontMenuItem.visible = largerFontMenuItem.enabled
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: minLoadingDelay
|
||||
interval: 1000
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: resetPager
|
||||
interval: 0
|
||||
onTriggered: {
|
||||
if (_currentPage >= 0) {
|
||||
console.log("resetting pager to", _currentPage)
|
||||
pager.currentPage = _currentPage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BookModel {
|
||||
id: bookModel
|
||||
book: root.book ? root.book : null
|
||||
size: bookListWatcher.size
|
||||
currentPage: _currentPage
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
topMargin: Theme.itemSizeSmall
|
||||
bottomMargin: Theme.itemSizeSmall
|
||||
settings: root.settings
|
||||
onJumpToPage: bookView.jumpTo(index)
|
||||
onCurrentPageChanged: {
|
||||
if (currentPage >= 0 && bookView._jumpingTo < 0) {
|
||||
pager.currentPage = currentPage
|
||||
}
|
||||
}
|
||||
onLoadingChanged: {
|
||||
if (loading && !pageCount) {
|
||||
minLoadingDelay.start()
|
||||
bookView._jumpingTo = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListWatcher {
|
||||
id: bookListWatcher
|
||||
listView: bookView
|
||||
}
|
||||
|
||||
SilicaListView {
|
||||
id: bookView
|
||||
model: bookModel
|
||||
anchors.fill: parent
|
||||
flickDeceleration: maximumFlickVelocity
|
||||
orientation: ListView.Horizontal
|
||||
snapMode: ListView.SnapOneItem
|
||||
spacing: Theme.paddingMedium
|
||||
opacity: _loading ? 0 : 1
|
||||
visible: opacity > 0
|
||||
delegate: BooksPageView {
|
||||
width: bookView.width
|
||||
height: bookView.height
|
||||
model: bookModel
|
||||
page: index
|
||||
settings: root.settings
|
||||
leftMargin: bookModel.leftMargin
|
||||
rightMargin: bookModel.rightMargin
|
||||
topMargin: bookModel.topMargin
|
||||
bottomMargin: bookModel.bottomMargin
|
||||
titleVisible: _currentState.title
|
||||
pageNumberVisible: _currentState.page
|
||||
title: bookModel.title
|
||||
onPageClicked: {
|
||||
root.pageClicked(index)
|
||||
settings.pageDetails = (settings.pageDetails+ 1) % _visibilityStates.length
|
||||
}
|
||||
}
|
||||
|
||||
property int _jumpingTo: -1
|
||||
function jumpTo(page) {
|
||||
if (page >=0 && page !== _currentPage) {
|
||||
_jumpingTo = page
|
||||
positionViewAtIndex(page, ListView.Center)
|
||||
_jumpingTo = -1
|
||||
if (_currentPage !== page) {
|
||||
console.log("oops, still at", _currentPage)
|
||||
resetPager.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
|
||||
/*
|
||||
BooksPageTools {
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: bookModel.leftMargin
|
||||
rightMargin: bookModel.rightMargin
|
||||
}
|
||||
opacity: _currentState.tools ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
*/
|
||||
|
||||
BooksPager {
|
||||
id: pager
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: (Theme.itemSizeExtraSmall + 2*(bookModel.bottomMargin - height))/4
|
||||
}
|
||||
pageCount: bookModel.pageCount
|
||||
width: parent.width
|
||||
opacity: _pagerVisible ? 1 : 0
|
||||
visible: opacity > 0
|
||||
onPageChanged: bookView.jumpTo(page)
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
|
||||
Column {
|
||||
id: loadingAnimation
|
||||
opacity: _loading ? 1 : 0
|
||||
visible: opacity > 0
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.paddingLarge
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
Item {
|
||||
width: busyIndicator.width
|
||||
height: busyIndicator.height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
BusyIndicator {
|
||||
id: busyIndicator
|
||||
anchors.centerIn: parent
|
||||
size: BusyIndicatorSize.Large
|
||||
running: _loading
|
||||
}
|
||||
BooksFitLabel {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: Theme.paddingMedium
|
||||
}
|
||||
maxFontSize: Theme.fontSizeMedium
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color: Theme.highlightColor
|
||||
text: bookModel.progress > 0 ? bookModel.progress : ""
|
||||
visible: opacity > 0
|
||||
opacity: bookModel.progress > 0 ? 1 : 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
}
|
||||
Label {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color: Theme.highlightColor
|
||||
//% "Loading..."
|
||||
text: qsTrId("book-view-loading")
|
||||
}
|
||||
}
|
||||
}
|
109
app/qml/BooksCoverPage.qml
Normal file
109
app/qml/BooksCoverPage.qml
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
CoverBackground {
|
||||
id: root
|
||||
transparent: !_haveBook || grid.count < 6
|
||||
|
||||
property variant book
|
||||
property variant shelf
|
||||
|
||||
property bool _haveBook: book ? true : false
|
||||
|
||||
CoverModel {
|
||||
id: coverModel
|
||||
source: shelf
|
||||
}
|
||||
|
||||
GridView {
|
||||
id: grid
|
||||
visible: !_haveBook
|
||||
anchors.fill: parent
|
||||
interactive: false
|
||||
cellWidth: Math.floor(width/2.0)
|
||||
cellHeight: Math.ceil(height/((grid.count > 4) ? 3.0 : 2.0))
|
||||
model: coverModel
|
||||
delegate: BookCover {
|
||||
book: model.book
|
||||
width: grid.cellWidth
|
||||
height: grid.cellHeight
|
||||
borderWidth: 0
|
||||
stretch: true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
visible: !_haveBook && !coverModel.count
|
||||
color: "#cc0000"
|
||||
height: Math.ceil(parent.height*3/10)
|
||||
width: height
|
||||
radius: height/2
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
source: "images/cover-image.svg"
|
||||
width: parent.width - Math.max(Math.ceil(parent.width/20),2)
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
}
|
||||
|
||||
BookCover {
|
||||
id: bookCover
|
||||
visible: _haveBook
|
||||
anchors.fill: parent
|
||||
anchors.centerIn: parent
|
||||
width: Theme.coverSizeLarge.width
|
||||
height: Theme.coverSizeLarge.height
|
||||
borderRadius: Theme.paddingSmall
|
||||
borderColor: Theme.primaryColor
|
||||
synchronous: true
|
||||
book: root.book ? root.book : null
|
||||
defaultCover: "images/default-cover.jpg"
|
||||
stretch: true
|
||||
}
|
||||
|
||||
BooksTitleText {
|
||||
anchors {
|
||||
margins: Theme.paddingMedium
|
||||
fill: parent
|
||||
}
|
||||
text: book ? book.title : ""
|
||||
visible: bookCover.empty
|
||||
}
|
||||
}
|
66
app/qml/BooksDeleteButton.qml
Normal file
66
app/qml/BooksDeleteButton.qml
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
signal clicked()
|
||||
|
||||
property real size
|
||||
property real margin: Theme.paddingMedium
|
||||
|
||||
width: size
|
||||
height: size
|
||||
color: Theme.highlightColor
|
||||
radius: size/2
|
||||
|
||||
opacity: enabled ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
source: "images/close-x.svg"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: -root.margin
|
||||
}
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
}
|
260
app/qml/BooksDragArea.qml
Normal file
260
app/qml/BooksDragArea.qml
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
MouseArea {
|
||||
id: root
|
||||
parent: dragInProgress ? dragParent : gridView
|
||||
anchors.fill: parent
|
||||
|
||||
signal deleteItemAt(var index)
|
||||
signal dropItem(var mouseX, var mouseY)
|
||||
|
||||
property var dragParent
|
||||
property var gridView
|
||||
property int draggedItemIndex: -1
|
||||
property int pressedItemIndex: -1
|
||||
property int pressedDeleteItemIndex: -1
|
||||
property int lastPressedItemScalingIndex: -1
|
||||
property int lastReleasedItemIndex: -1
|
||||
property int lastReleasedDeleteItemIndex: -1
|
||||
property bool pressedItemScaling: (pressedItemIndex >= 0 && lastPressedItemScalingIndex === pressedItemIndex)
|
||||
property bool dragPositionChanged
|
||||
property bool dragCloseToTheLeftEdge
|
||||
property bool dragCloseToTheRightEdge
|
||||
property real dragLastX
|
||||
property real dragLastY
|
||||
|
||||
onDraggedItemIndexChanged: {
|
||||
draggedItem = (draggedItemIndex >= 0) ? shelf.get(draggedItemIndex) : null
|
||||
}
|
||||
|
||||
function itemX(index) { return shelfView.cellWidth * (index % shelfView._cellsPerRow) - gridView.contentX }
|
||||
function itemY(index) { return shelfView.cellHeight * Math.floor(index / shelfView._cellsPerRow) - gridView.contentY }
|
||||
|
||||
onCanceled: {
|
||||
stopDrag()
|
||||
}
|
||||
onClicked: {
|
||||
var index
|
||||
if (shelfView.editMode) {
|
||||
if (!dragInProgress || !dragPositionChanged) {
|
||||
index = gridView.indexAt(mouseX + gridView.contentX, mouseY + currentShelfView.contentY)
|
||||
if (index >= 0 &&
|
||||
index === lastReleasedDeleteItemIndex &&
|
||||
dragItem.withinDeleteButton(mouseX - itemX(index), mouseY - itemY(index))) {
|
||||
lastReleasedDeleteItemIndex = -1
|
||||
root.deleteItemAt(index)
|
||||
dragScrollAnimation.stop()
|
||||
} else if (shelfView.shelf.deleteRequested(index)) {
|
||||
shelfView.shelf.setDeleteRequested(index, false);
|
||||
} else {
|
||||
shelfView.stopEditing()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
index = gridView.indexAt(mouseX + gridView.contentX, mouseY + currentShelfView.contentY)
|
||||
if (index >= 0 && index === lastReleasedItemIndex) {
|
||||
var item = shelf.get(index);
|
||||
if (item.book && item.accessible) {
|
||||
shelfView.openBook(item.book)
|
||||
}
|
||||
}
|
||||
}
|
||||
resetPressState()
|
||||
dragScrollAnimation.stop()
|
||||
}
|
||||
onPressed: {
|
||||
var index = gridView.indexAt(mouseX + gridView.contentX, mouseY + currentShelfView.contentY)
|
||||
lastReleasedItemIndex = -1
|
||||
lastReleasedDeleteItemIndex = -1
|
||||
pressedItemIndex = index
|
||||
if (pressedDeleteItemIndex < 0 &&
|
||||
dragItem.withinDeleteButton(mouseX - itemX(index), mouseY - itemY(index))) {
|
||||
pressedDeleteItemIndex = index
|
||||
} else {
|
||||
pressedDeleteItemIndex = -1
|
||||
}
|
||||
}
|
||||
onReleased: {
|
||||
stopDrag(mouseX, mouseY)
|
||||
}
|
||||
onPressAndHold: {
|
||||
if (!shelfView.editMode) {
|
||||
var index = gridView.indexAt(mouseX + gridView.contentX, mouseY + currentShelfView.contentY)
|
||||
if (index === pressedItemIndex) {
|
||||
shelfView.startEditing()
|
||||
}
|
||||
}
|
||||
}
|
||||
onPositionChanged: {
|
||||
if (shelfView.editMode) {
|
||||
if (!pressedItemScaling && !dragInProgress && pressedDeleteItemIndex < 0) {
|
||||
startDrag(mouseX, mouseY)
|
||||
} else {
|
||||
doDrag(mouseX, mouseY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startDrag(x, y) {
|
||||
var index = gridView.indexAt(x + gridView.contentX, y + currentShelfView.contentY)
|
||||
if (index >= 0) {
|
||||
var item = shelf.get(index)
|
||||
if (item.accessible) {
|
||||
var delta = gridView.mapToItem(dragParent,0,0)
|
||||
console.log(shelf.path, "dragging", item.name)
|
||||
dragLastX = x + delta.x
|
||||
dragLastY = y + delta.y
|
||||
dragItem.moveAnimationEnabled = false
|
||||
dragItem.shelfIndex = shelfView.shelfIndex
|
||||
dragItem.dropShelfIndex = -1
|
||||
dragItem.dropItemIndex = -1
|
||||
dragItem.x = itemX(index) + delta.x
|
||||
dragItem.y = itemY(index) + delta.y
|
||||
dragCloseToTheLeftEdge = (x < horizontalScrollThreshold)
|
||||
dragCloseToTheRightEdge = (x > (gridView.width - horizontalScrollThreshold))
|
||||
dragPositionChanged = false
|
||||
draggedItemIndex = index
|
||||
pressedItemIndex = -1
|
||||
dragItem.visible = true
|
||||
} else {
|
||||
console.log(item.name, "is not draggable")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doDrag(x, y) {
|
||||
if (dragInProgress && !dragItem.moving) {
|
||||
var dx = x - dragLastX
|
||||
var dy = y - dragLastY
|
||||
if (dx !== 0 || dy !== 0) {
|
||||
dragPositionChanged = true
|
||||
dragItem.x += dx
|
||||
dragItem.y += dy
|
||||
dragLastX = x
|
||||
dragLastY = y
|
||||
var newIndex = currentShelfView.indexAt(x + gridView.contentX, Math.max(y + currentShelfView.contentY, 0))
|
||||
if (newIndex < 0) newIndex = currentShelf.count - 1
|
||||
if (newIndex >= 0) {
|
||||
if (currentShelf.hasDummyItem) {
|
||||
currentShelf.dummyItemIndex = newIndex
|
||||
} else {
|
||||
currentShelf.move(draggedItemIndex, newIndex)
|
||||
draggedItemIndex = newIndex
|
||||
}
|
||||
}
|
||||
if (y < verticalScrollThreshold && currentShelfView.contentY > 0) {
|
||||
if (!dragScrollAnimation.running) {
|
||||
dragScrollAnimation.from = currentShelfView.contentY
|
||||
dragScrollAnimation.to = 0
|
||||
dragScrollAnimation.duration = currentShelfView.contentY*1000/gridView.height
|
||||
dragScrollAnimation.start()
|
||||
}
|
||||
} else if (y > (gridView.height - verticalScrollThreshold) && (currentShelfView.contentY < maxContentY)) {
|
||||
if (!dragScrollAnimation.running) {
|
||||
dragScrollAnimation.from = currentShelfView.contentY
|
||||
dragScrollAnimation.to = maxContentY
|
||||
dragScrollAnimation.duration = (maxContentY - currentShelfView.contentY)*1000/gridView.height
|
||||
dragScrollAnimation.start()
|
||||
}
|
||||
} else {
|
||||
if (dragScrollAnimation.running) {
|
||||
dragScrollAnimation.stop()
|
||||
}
|
||||
if (x < horizontalScrollThreshold) {
|
||||
if (!dragCloseToTheLeftEdge) {
|
||||
dragCloseToTheLeftEdge = true
|
||||
shelfView.scrollLeft()
|
||||
}
|
||||
} else {
|
||||
dragCloseToTheLeftEdge = false
|
||||
}
|
||||
if (x > (gridView.width - horizontalScrollThreshold)) {
|
||||
if (!dragCloseToTheRightEdge) {
|
||||
dragCloseToTheRightEdge = true
|
||||
shelfView.scrollRight()
|
||||
}
|
||||
} else {
|
||||
dragCloseToTheRightEdge = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopDrag(x, y) {
|
||||
lastReleasedItemIndex = pressedItemIndex
|
||||
lastReleasedDeleteItemIndex = pressedDeleteItemIndex
|
||||
if (draggedItemIndex >= 0) {
|
||||
if (x !== undefined && y !== undefined) doDrag(x, y)
|
||||
var delta = gridView.mapToItem(dragParent,0,0)
|
||||
dragItem.moveAnimationEnabled = true
|
||||
dragItem.x = itemX(draggedItemIndex) + delta.x
|
||||
dragItem.y = itemY(draggedItemIndex) + delta.y
|
||||
// Allow the listener to modify dragItem coordinates
|
||||
if (x !== undefined && y !== undefined) root.dropItem(x,y)
|
||||
dragItem.dragged = false
|
||||
// Normally we would finish things up once all the
|
||||
// animations have completed
|
||||
if (!dragItem.animating) finishDrag()
|
||||
}
|
||||
pressedItemIndex = -1
|
||||
dragScrollAnimation.stop()
|
||||
}
|
||||
|
||||
function finishDrag() {
|
||||
console.log(shelf.path, "done with drag animation")
|
||||
draggedItemIndex = -1
|
||||
dragItem.dropShelfIndex = -1
|
||||
dragItem.dropItemIndex = -1
|
||||
dragItem.moveAnimationEnabled = false
|
||||
dragItem.visible = false
|
||||
}
|
||||
|
||||
function resetPressState() {
|
||||
pressedItemIndex = -1
|
||||
pressedDeleteItemIndex = -1
|
||||
lastReleasedItemIndex = -1
|
||||
lastReleasedDeleteItemIndex = -1
|
||||
dragCloseToTheLeftEdge = false
|
||||
dragCloseToTheRightEdge = false
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: dragScrollAnimation
|
||||
target: currentShelfView
|
||||
property: "contentY"
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
66
app/qml/BooksFitLabel.qml
Normal file
66
app/qml/BooksFitLabel.qml
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
Label {
|
||||
property int minFontSize: Theme.fontSizeTiny
|
||||
property int maxFontSize: Theme.fontSizeHuge
|
||||
|
||||
smooth: true
|
||||
|
||||
Component.onCompleted: refitText()
|
||||
|
||||
onWidthChanged: refitText()
|
||||
onHeightChanged: refitText()
|
||||
onTextChanged: refitText()
|
||||
onMaxFontSizeChanged: refitText()
|
||||
onMinFontSizeChanged: refitText()
|
||||
|
||||
function refitText() {
|
||||
if (paintedHeight > 0 && paintedWidth > 0) {
|
||||
if (font.pixelSize % 2) font.pixelSize++
|
||||
while (paintedWidth > width || paintedHeight > height) {
|
||||
if ((font.pixelSize -= 2) <= minFontSize)
|
||||
break
|
||||
}
|
||||
while (paintedWidth < width && paintedHeight < height) {
|
||||
font.pixelSize += 2
|
||||
}
|
||||
font.pixelSize -= 2
|
||||
if (font.pixelSize >= maxFontSize) {
|
||||
font.pixelSize = maxFontSize
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
118
app/qml/BooksImport.qml
Normal file
118
app/qml/BooksImport.qml
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
allowedOrientations: window.allowedOrientations
|
||||
canAccept: importModel.selectedCount > 0
|
||||
|
||||
property alias selectedCount: importModel.selectedCount
|
||||
property alias destination: importModel.destination
|
||||
|
||||
property bool _loading: importModel.busy || startTimer.running
|
||||
|
||||
function selectedBook(index) { return importModel.selectedBook(index) }
|
||||
|
||||
BooksImportModel {
|
||||
id: importModel
|
||||
}
|
||||
|
||||
SilicaFlickable {
|
||||
anchors.fill: parent
|
||||
|
||||
DialogHeader {
|
||||
id: dialogHeader
|
||||
spacing: 0
|
||||
acceptText: (_loading || !importModel.count) ? "" :
|
||||
//% "Import %0 book(s)"
|
||||
importModel.selectedCount ? qsTrId("import-view-import-n-books",importModel.selectedCount).arg(importModel.selectedCount) :
|
||||
//% "Select books"
|
||||
qsTrId("import-view-select-books")
|
||||
}
|
||||
|
||||
SilicaListView {
|
||||
anchors {
|
||||
top: dialogHeader.bottom
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
model: importModel
|
||||
clip: true
|
||||
|
||||
opacity: (importModel.count > 0) ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
|
||||
delegate: BooksImportItem {
|
||||
width: root.width
|
||||
highlighted: down || model.selected
|
||||
contentHeight: Theme.itemSizeExtraLarge
|
||||
onClicked: importModel.setSelected(model.index, !model.selected)
|
||||
book: model.book
|
||||
}
|
||||
VerticalScrollDecorator {}
|
||||
}
|
||||
|
||||
ViewPlaceholder {
|
||||
//% "No new books found"
|
||||
text: qsTrId("import-view-no-new-books-found")
|
||||
enabled: !_loading && !importModel.count
|
||||
}
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
visible: opacity > 0
|
||||
anchors.centerIn: parent
|
||||
size: BusyIndicatorSize.Large
|
||||
running: _loading && !importModel.count
|
||||
}
|
||||
|
||||
// Give the dialog 1 second to initialize and finish the transition
|
||||
// then ask the model to actually examine the downloads
|
||||
Timer {
|
||||
interval: 1000
|
||||
running: true
|
||||
onTriggered: importModel.refresh()
|
||||
}
|
||||
|
||||
// Then show the spinner for at least one more second
|
||||
Timer {
|
||||
id: startTimer
|
||||
interval: 2000
|
||||
running: true
|
||||
}
|
||||
}
|
101
app/qml/BooksImportItem.qml
Normal file
101
app/qml/BooksImportItem.qml
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
BackgroundItem {
|
||||
id: root
|
||||
width: parent.width
|
||||
height: contentHeight
|
||||
enabled: book ? true : false
|
||||
|
||||
property var book
|
||||
property string _title: book ? book.title : ""
|
||||
property string _authors: book ? book.authors : ""
|
||||
|
||||
BooksShelfItem {
|
||||
id: cover
|
||||
visible: root.enabled
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
}
|
||||
width: Math.round(height*3/4)
|
||||
book: root.book ? root.book : null
|
||||
name: _title
|
||||
}
|
||||
|
||||
Column {
|
||||
visible: root.enabled
|
||||
anchors {
|
||||
left: cover.right
|
||||
leftMargin: Theme.paddingMedium
|
||||
right: parent.right
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
Label {
|
||||
width: parent.width
|
||||
text: _authors
|
||||
color: root.highlighted ? Theme.highlightColor : Theme.primaryColor
|
||||
truncationMode: TruncationMode.Fade
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
}
|
||||
Label {
|
||||
width: parent.width
|
||||
text: _title
|
||||
color: root.highlighted ? Theme.highlightColor : Theme.primaryColor
|
||||
truncationMode: TruncationMode.Fade
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: Theme.paddingSmall
|
||||
right: parent.right
|
||||
rightMargin: Theme.paddingSmall
|
||||
}
|
||||
visible: highlighted
|
||||
source: "image://theme/icon-s-installed" + (highlighted ? "?" + Theme.highlightColor : "")
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
visible: !root.enabled
|
||||
running: visible
|
||||
size: BusyIndicatorSize.Medium
|
||||
}
|
||||
}
|
55
app/qml/BooksMain.qml
Normal file
55
app/qml/BooksMain.qml
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
allowedOrientations: Orientation.All
|
||||
|
||||
property variant currentShelf: mainPage.currentShelf
|
||||
|
||||
Settings { id: globalSettings }
|
||||
|
||||
initialPage: BooksMainPage {
|
||||
id: mainPage
|
||||
settings: globalSettings
|
||||
}
|
||||
|
||||
cover: Component {
|
||||
BooksCoverPage {
|
||||
book: globalSettings.currentBook
|
||||
shelf: currentShelf
|
||||
}
|
||||
}
|
||||
}
|
82
app/qml/BooksMainPage.qml
Normal file
82
app/qml/BooksMainPage.qml
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
allowedOrientations: window.allowedOrientations
|
||||
|
||||
//property variant shelf
|
||||
property variant settings
|
||||
property variant currentShelf: storageView.currentShelf
|
||||
|
||||
property Item _bookView
|
||||
|
||||
function createBookViewIfNeeded() {
|
||||
if (settings.currentBook && !_bookView) {
|
||||
_bookView = bookViewComponent.createObject(root)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: settings
|
||||
onCurrentBookChanged: createBookViewIfNeeded()
|
||||
}
|
||||
|
||||
Component {
|
||||
id: bookViewComponent
|
||||
BooksBookView {
|
||||
anchors.fill: parent
|
||||
opacity: book ? 1 : 0
|
||||
visible: opacity > 0
|
||||
settings: root.settings
|
||||
book: settings.currentBook ? settings.currentBook : null
|
||||
onCloseBook: settings.currentBook = null
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
}
|
||||
|
||||
BooksStorageView {
|
||||
id: storageView
|
||||
anchors.fill: parent
|
||||
settings: root.settings
|
||||
opacity: settings.currentBook ? 0 : 1
|
||||
visible: opacity > 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
onOpenBook: settings.currentBook = book
|
||||
}
|
||||
|
||||
Component.onCompleted: createBookViewIfNeeded()
|
||||
}
|
287
app/qml/BooksPageSlider.qml
Normal file
287
app/qml/BooksPageSlider.qml
Normal file
|
@ -0,0 +1,287 @@
|
|||
/****************************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Jolla Ltd.
|
||||
** Contact: Martin Jones <martin.jones@jollamobile.com>
|
||||
** All rights reserved.
|
||||
**
|
||||
** This file is part of Sailfish Silica UI component package.
|
||||
**
|
||||
** You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
**
|
||||
****************************************************************************************/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
MouseArea {
|
||||
id: slider
|
||||
|
||||
// Same as Silica Slider except that its colors are configurable
|
||||
property color primaryColor: Theme.primaryColor
|
||||
property color secondaryColor: Theme.secondaryColor
|
||||
property color highlightColor: Theme.highlightColor
|
||||
property color secondaryHighlightColor: Theme.secondaryHighlightColor
|
||||
|
||||
property real maximumValue: 1.0
|
||||
property real minimumValue: 0.0
|
||||
property real stepSize
|
||||
property real value: 0.0
|
||||
readonly property real sliderValue: Math.max(minimumValue, Math.min(maximumValue, value))
|
||||
property bool handleVisible: true
|
||||
property string valueText
|
||||
property alias label: labelText.text
|
||||
property bool down: pressed
|
||||
property bool highlighted: down
|
||||
property real leftMargin: Math.round(Screen.width/8)
|
||||
property real rightMargin: Math.round(Screen.width/8)
|
||||
|
||||
property bool _hasValueLabel: false
|
||||
property real _oldValue
|
||||
property bool _tracking: true
|
||||
property real _precFactor: 1.0
|
||||
|
||||
property real _grooveWidth: Math.max(0, width - leftMargin - rightMargin)
|
||||
property bool _widthChanged
|
||||
property bool _cancel
|
||||
|
||||
property bool _componentComplete
|
||||
|
||||
onStepSizeChanged: {
|
||||
// Avoid rounding errors. We assume that the range will
|
||||
// be sensibly related to stepSize
|
||||
var decimial = Math.floor(stepSize) - stepSize
|
||||
if (decimial < 0.001) {
|
||||
_precFactor = Math.pow(10, 7)
|
||||
} else if (decimial < 0.1) {
|
||||
_precFactor = Math.pow(10, 4)
|
||||
} else {
|
||||
_precFactor = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
height: valueText !== "" ? Theme.itemSizeExtraLarge : label !== "" ? Theme.itemSizeMedium : Theme.itemSizeSmall
|
||||
|
||||
onWidthChanged: updateWidth()
|
||||
onLeftMarginChanged: updateWidth()
|
||||
onRightMarginChanged: updateWidth()
|
||||
|
||||
// changing the width of the slider shouldn't animate the slider bar/handle
|
||||
function updateWidth() {
|
||||
_widthChanged = true
|
||||
_grooveWidth = Math.max(0, width - leftMargin - rightMargin)
|
||||
_widthChanged = false
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
_cancel = true
|
||||
value = _oldValue
|
||||
_updateHighlightToValue()
|
||||
}
|
||||
|
||||
drag {
|
||||
target: draggable
|
||||
minimumX: leftMargin - highlight.width/2
|
||||
maximumX: slider.width - leftMargin - highlight.width/2
|
||||
axis: Drag.XAxis
|
||||
}
|
||||
|
||||
function _updateHighlightToValue() {
|
||||
if (maximumValue > minimumValue) {
|
||||
highlight.x = (sliderValue - minimumValue) / (maximumValue - minimumValue) * _grooveWidth - highlight.width/2 + leftMargin
|
||||
} else {
|
||||
highlight.x = leftMargin - highlight.width/2
|
||||
}
|
||||
}
|
||||
|
||||
function _updateValueToDraggable() {
|
||||
if (width > (leftMargin + rightMargin)) {
|
||||
highlight.x = draggable.x
|
||||
var pos = draggable.x + highlight.width/2 - leftMargin
|
||||
value = _calcValue((pos / _grooveWidth) * (maximumValue - minimumValue) + minimumValue)
|
||||
}
|
||||
}
|
||||
|
||||
function _calcValue(newVal) {
|
||||
if (newVal <= minimumValue) {
|
||||
return minimumValue
|
||||
}
|
||||
|
||||
if (stepSize > 0.0) {
|
||||
var offset = newVal - minimumValue
|
||||
var intervals = Math.round(offset / stepSize)
|
||||
newVal = Math.round((minimumValue + (intervals * stepSize)) * _precFactor) / _precFactor
|
||||
}
|
||||
|
||||
if (newVal > maximumValue) {
|
||||
return maximumValue
|
||||
}
|
||||
|
||||
return newVal
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
_cancel = false
|
||||
_oldValue = value
|
||||
draggable.x = Math.min(Math.max(drag.minimumX, mouseX - highlight.width/2), drag.maximumX)
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
if (!_cancel) {
|
||||
_tracking = false
|
||||
_updateValueToDraggable()
|
||||
if (stepSize != 0.0) {
|
||||
// on release make sure that we settle on a step boundary
|
||||
_updateHighlightToValue()
|
||||
}
|
||||
_oldValue = value
|
||||
}
|
||||
}
|
||||
|
||||
onCanceled: value = _oldValue
|
||||
|
||||
onValueTextChanged: {
|
||||
if (valueText && !_hasValueLabel) {
|
||||
_hasValueLabel = true
|
||||
var valueIndicatorComponent = Qt.createComponent("private/SliderValueLabel.qml")
|
||||
if (valueIndicatorComponent.status === Component.Ready) {
|
||||
valueIndicatorComponent.createObject(slider)
|
||||
} else {
|
||||
console.log(valueIndicatorComponent.errorString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onSliderValueChanged: {
|
||||
if (!slider.drag.active) {
|
||||
_tracking = false
|
||||
_updateHighlightToValue()
|
||||
}
|
||||
}
|
||||
|
||||
GlassItem {
|
||||
id: background
|
||||
// extra painting margins (Theme.paddingMedium on both sides) are needed,
|
||||
// because glass item doesn't visibly paint across the full width of the item
|
||||
x: slider.leftMargin-Theme.paddingMedium
|
||||
width: slider._grooveWidth + 2*Theme.paddingMedium
|
||||
height: Theme.itemSizeExtraSmall/2
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
dimmed: true
|
||||
radius: 0.06
|
||||
falloffRadius: 0.09
|
||||
ratio: 0.0
|
||||
onWidthChanged: { _tracking = true; _updateHighlightToValue() }
|
||||
color: slider.highlighted ? highlightColor : secondaryColor
|
||||
states: State {
|
||||
name: "hasText"; when: slider.valueText !== "" || text !== ""
|
||||
AnchorChanges { target: background; anchors.verticalCenter: undefined; anchors.bottom: slider.bottom }
|
||||
PropertyChanges { target: background; anchors.bottomMargin: Theme.fontSizeSmall + Theme.paddingSmall + 1 }
|
||||
}
|
||||
}
|
||||
|
||||
GlassItem {
|
||||
id: progressBar
|
||||
x: background.x // some margin at each end
|
||||
anchors.verticalCenter: background.verticalCenter
|
||||
// height added as GlassItem will not display correctly with width < height
|
||||
width: (sliderValue - minimumValue) / (maximumValue - minimumValue) * (background.width-height) + height
|
||||
height: Theme.itemSizeExtraSmall/2
|
||||
visible: sliderValue > minimumValue
|
||||
dimmed: false
|
||||
radius: 0.05
|
||||
falloffRadius: 0.14
|
||||
ratio: 0.0
|
||||
color: slider.highlighted ? highlightColor : primaryColor
|
||||
Behavior on width {
|
||||
enabled: !_widthChanged
|
||||
SmoothedAnimation { velocity: 1500 }
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: draggable
|
||||
width: highlight.width
|
||||
height: highlight.height
|
||||
onXChanged: {
|
||||
if (_cancel) {
|
||||
return
|
||||
}
|
||||
if (slider.drag.active) {
|
||||
_updateValueToDraggable()
|
||||
}
|
||||
if (!_tracking && Math.abs(highlight.x - draggable.x) < 5) {
|
||||
_tracking = true
|
||||
}
|
||||
}
|
||||
}
|
||||
GlassItem {
|
||||
id: highlight
|
||||
width: Theme.itemSizeMedium
|
||||
height: Theme.itemSizeMedium
|
||||
radius: 0.17
|
||||
falloffRadius: 0.17
|
||||
anchors.verticalCenter: background.verticalCenter
|
||||
visible: handleVisible
|
||||
color: slider.highlighted ? highlightColor : primaryColor
|
||||
Behavior on x {
|
||||
enabled: !_widthChanged
|
||||
SmoothedAnimation { velocity: 1500 }
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: labelText
|
||||
visible: text.length
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: slider.highlighted ? secondaryHighlightColor : secondaryColor
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: background.verticalCenter
|
||||
anchors.topMargin: Theme.paddingMedium
|
||||
width: Math.min(paintedWidth, parent.width - 2*Theme.paddingMedium)
|
||||
truncationMode: TruncationMode.Fade
|
||||
}
|
||||
states: State {
|
||||
name: "invalidRange"
|
||||
when: _componentComplete && minimumValue >= maximumValue
|
||||
PropertyChanges {
|
||||
target: progressBar
|
||||
width: progressBar.height
|
||||
}
|
||||
PropertyChanges {
|
||||
target: slider
|
||||
enabled: false
|
||||
opacity: 0.6
|
||||
}
|
||||
StateChangeScript {
|
||||
script: console.log("Warning: Slider.maximumValue needs to be higher than Slider.minimumValue")
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
_componentComplete = true
|
||||
_updateHighlightToValue()
|
||||
}
|
||||
}
|
107
app/qml/BooksPageView.qml
Normal file
107
app/qml/BooksPageView.qml
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
Item {
|
||||
id: view
|
||||
|
||||
property alias model: widget.model
|
||||
property alias page: widget.page
|
||||
property alias leftMargin: widget.leftMargin
|
||||
property alias rightMargin: widget.rightMargin
|
||||
property alias topMargin: widget.topMargin
|
||||
property alias bottomMargin: widget.bottomMargin
|
||||
property alias settings: widget.settings
|
||||
property alias title: titleLabel.text
|
||||
property bool titleVisible
|
||||
property bool pageNumberVisible
|
||||
property color extraInfoColor: "#808080"
|
||||
|
||||
signal pageClicked()
|
||||
|
||||
PageWidget {
|
||||
id: widget
|
||||
anchors.fill: parent
|
||||
model: bookModel
|
||||
}
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: Theme.paddingLarge
|
||||
rightMargin: Theme.paddingLarge
|
||||
}
|
||||
height: Theme.itemSizeExtraSmall
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: extraInfoColor
|
||||
elide: Text.ElideRight
|
||||
opacity: titleVisible ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
size: BusyIndicatorSize.Large
|
||||
running: widget.loading
|
||||
opacity: running ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity {}
|
||||
}
|
||||
|
||||
Label {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
}
|
||||
text: widget.page + 1
|
||||
height: Theme.itemSizeExtraSmall
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: extraInfoColor
|
||||
opacity: pageNumberVisible ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: view.pageClicked()
|
||||
}
|
||||
}
|
68
app/qml/BooksPager.qml
Normal file
68
app/qml/BooksPager.qml
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
height: slider.height
|
||||
|
||||
property alias pageCount: slider.maximumValue
|
||||
property alias currentPage: slider.value
|
||||
property alias pressed: slider.pressed
|
||||
property alias leftMargin: slider.leftMargin
|
||||
property alias rightMargin: slider.rightMargin
|
||||
|
||||
signal pageChanged(var page)
|
||||
|
||||
BooksPageSlider {
|
||||
id: slider
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
stepSize: 1
|
||||
minimumValue: 0
|
||||
valueText: ""
|
||||
label: ""
|
||||
//highlightColor: primaryColor
|
||||
//secondaryHighlightColor: secondaryColor
|
||||
//highlightColor: "#000000"
|
||||
//secondaryHighlightColor: "#808080"
|
||||
//primaryColor: "#808080"
|
||||
primaryColor: highlightColor
|
||||
secondaryColor: secondaryHighlightColor
|
||||
onValueChanged: root.pageChanged(value)
|
||||
}
|
||||
}
|
54
app/qml/BooksSDCardIcon.qml
Normal file
54
app/qml/BooksSDCardIcon.qml
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
width: image.width
|
||||
|
||||
Rectangle {
|
||||
color: Theme.highlightColor
|
||||
x: parent.width*3/80
|
||||
y: parent.height*3/60
|
||||
width: parent.width*74/80
|
||||
height: parent.height*47/60
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image
|
||||
height: parent.height
|
||||
sourceSize.height: height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "images/sdcard.svg"
|
||||
}
|
||||
}
|
205
app/qml/BooksShelfItem.qml
Normal file
205
app/qml/BooksShelfItem.qml
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
signal clicked()
|
||||
signal deleteRequested()
|
||||
signal deleteMe()
|
||||
|
||||
opacity: deletingAll ? deleteAllOpacity : deleting ? scale : 1
|
||||
|
||||
property alias name: title.text
|
||||
property alias book: cover.book
|
||||
property alias synchronous: cover.synchronous
|
||||
property alias remorseTimeout: deleteAnimation.duration
|
||||
property real margins: Theme.paddingMedium
|
||||
property real deleteAllOpacity: 1
|
||||
property bool editMode
|
||||
property bool dropped
|
||||
property bool dragged
|
||||
property bool pressed
|
||||
property bool deletingAll
|
||||
property bool deleting
|
||||
property bool copyingOut
|
||||
property bool copyingIn
|
||||
property bool scaleAnimationEnabled: true
|
||||
property bool moveAnimationEnabled: false
|
||||
|
||||
readonly property bool scaling: scaleUpAnimation.running || scaleDownAnimation.running || deleteAnimation.running
|
||||
readonly property bool moving: moveAnimationX.running || moveAnimationY.running
|
||||
readonly property bool animating: scaling || moving
|
||||
|
||||
property bool _deleting: deleting && !deletingAll
|
||||
property real _borderRadius: Theme.paddingSmall
|
||||
property color _borderColor: Theme.primaryColor
|
||||
|
||||
property bool scaledDown: (editMode && !dragged && !pressed && !dropped)
|
||||
|
||||
BookCover {
|
||||
id: cover
|
||||
anchors {
|
||||
margins: root.margins
|
||||
fill: parent
|
||||
}
|
||||
borderWidth: 2
|
||||
borderRadius: _borderRadius
|
||||
borderColor: _borderColor
|
||||
opacity: (copyingIn || copyingOut) ? 0.1 : 1
|
||||
Behavior on opacity { FadeAnimation { } }
|
||||
|
||||
BooksTitleText {
|
||||
id: title
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - 2*Theme.paddingMedium
|
||||
height: parent.height - 2*Theme.paddingMedium
|
||||
visible: parent.empty
|
||||
}
|
||||
|
||||
layer.enabled: root.pressed
|
||||
layer.effect: ShaderEffect { // i.e. PressEffect from Lipstick
|
||||
property variant source
|
||||
property color color: Theme.rgba(Theme.highlightBackgroundColor, 0.4)
|
||||
fragmentShader: "
|
||||
uniform sampler2D source;
|
||||
uniform highp vec4 color;
|
||||
uniform lowp float qt_Opacity;
|
||||
varying highp vec2 qt_TexCoord0;
|
||||
void main(void) {
|
||||
highp vec4 pixelColor = texture2D(source, qt_TexCoord0);
|
||||
gl_FragColor = vec4(mix(pixelColor.rgb/max(pixelColor.a, 0.00390625), color.rgb/max(color.a, 0.00390625), color.a) * pixelColor.a, pixelColor.a) * qt_Opacity;
|
||||
}"
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: -Theme.paddingSmall
|
||||
}
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
BooksDeleteButton {
|
||||
id: deleteButton
|
||||
x: cover.x + (cover.width - width)/2
|
||||
y: cover.y + cover.height - height/2
|
||||
size: 3*margins
|
||||
enabled: editMode && !pressed && !deleting && !deletingAll && !copyingIn && !copyingOut
|
||||
onClicked: root.deleteRequested()
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
id: busyIndicator
|
||||
anchors.centerIn: parent
|
||||
size: BusyIndicatorSize.Large
|
||||
running: copyingIn || copyingOut
|
||||
}
|
||||
|
||||
function withinDeleteButton(x, y) {
|
||||
return x >= deleteButton.x - deleteButton.margin &&
|
||||
x < deleteButton.x + deleteButton.width + deleteButton.margin &&
|
||||
y >= deleteButton.y - deleteButton.margin &&
|
||||
y < deleteButton.y + deleteButton.height + deleteButton.margin;
|
||||
}
|
||||
|
||||
function updateScaledDown() {
|
||||
if (scaleAnimationEnabled) {
|
||||
if (scaledDown) {
|
||||
scaleUpAnimation.stop()
|
||||
scaleDownAnimation.restart()
|
||||
} else {
|
||||
scaleDownAnimation.stop()
|
||||
scaleUpAnimation.restart()
|
||||
}
|
||||
} else {
|
||||
scale = scaledDown ? scaleDownAnimation.to : scaleUpAnimation.to
|
||||
}
|
||||
}
|
||||
|
||||
onScaledDownChanged: if (!_deleting) updateScaledDown()
|
||||
|
||||
onScaleAnimationEnabledChanged: {
|
||||
if (!_deleting && !scaleAnimationEnabled) {
|
||||
scale = scaledDown ? scaleDownAnimation.to : scaleUpAnimation.to
|
||||
}
|
||||
}
|
||||
|
||||
on_DeletingChanged: {
|
||||
if (_deleting) {
|
||||
scaleUpAnimation.stop()
|
||||
scaleDownAnimation.stop()
|
||||
deleteAnimation.start()
|
||||
} else {
|
||||
deleteAnimation.stop()
|
||||
updateScaledDown()
|
||||
}
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: scaleUpAnimation
|
||||
target: root
|
||||
property: "scale"
|
||||
to: 1
|
||||
duration: 250
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: scaleDownAnimation
|
||||
target: root
|
||||
property: "scale"
|
||||
to: 0.9
|
||||
duration: 250
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: deleteAnimation
|
||||
target: root
|
||||
property: "scale"
|
||||
to: 0
|
||||
duration: 2000
|
||||
easing.type: Easing.OutSine
|
||||
onRunningChanged: if (!running && _deleting) root.deleteMe()
|
||||
}
|
||||
|
||||
NumberAnimation { id: moveAnimationX; duration: 150; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { id: moveAnimationY; duration: 150; easing.type: Easing.InOutQuad }
|
||||
|
||||
Behavior on x { animation: moveAnimationX; enabled: moveAnimationEnabled }
|
||||
Behavior on y { animation: moveAnimationY; enabled: moveAnimationEnabled }
|
||||
}
|
258
app/qml/BooksShelfView.qml
Normal file
258
app/qml/BooksShelfView.qml
Normal file
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
SilicaFlickable {
|
||||
id: shelfView
|
||||
|
||||
property variant settings
|
||||
property int shelfIndex
|
||||
property bool singleStorage
|
||||
property bool removableStorage
|
||||
property bool editMode
|
||||
property bool deleteAllRequest
|
||||
property real cellWidth
|
||||
property real cellHeight
|
||||
property alias view: grid
|
||||
property alias shelf: shelfModel
|
||||
property alias device: shelfModel.device
|
||||
property alias dummyItemIndex: shelfModel.dummyItemIndex
|
||||
|
||||
signal openBook(var book)
|
||||
signal dropItem(var mouseX, var mouseY)
|
||||
signal startEditing()
|
||||
signal stopEditing()
|
||||
signal cancelDeleteAll()
|
||||
signal scrollRight()
|
||||
signal scrollLeft()
|
||||
|
||||
property bool _haveBooks: shelf && shelf.count
|
||||
property int _cellsPerRow: Math.floor(width/cellWidth)
|
||||
readonly property int _remorseTimeout: 5000
|
||||
property bool _loading: !shelf || shelf.loading || startAnimationTimer.running
|
||||
property var _remorse
|
||||
|
||||
on_HaveBooksChanged: if (!_haveBooks) shelfView.stopEditing()
|
||||
|
||||
Shelf {
|
||||
id: shelfModel
|
||||
property bool needDummyItem: dragInProgress && dragItem.shelfIndex !== shelfView.shelfIndex
|
||||
onNeedDummyItemChanged: if (needDummyItem) hasDummyItem = true
|
||||
editMode: shelfView.editMode
|
||||
}
|
||||
|
||||
onEditModeChanged: {
|
||||
dragItem.visible = false
|
||||
shelf.cancelAllDeleteRequests()
|
||||
dragArea.draggedItemIndex = -1
|
||||
fadeAnimation.stop()
|
||||
if (!editMode) {
|
||||
dragArea.resetPressState()
|
||||
dragScrollAnimation.stop()
|
||||
if (_remorse) _remorse.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
function doDeleteAll() {
|
||||
if (deleteAllRequest) {
|
||||
fadeAnimation.stop()
|
||||
shelf.removeAll()
|
||||
shelf.cancelAllDeleteRequests()
|
||||
}
|
||||
}
|
||||
|
||||
onDeleteAllRequestChanged: {
|
||||
if (deleteAllRequest) {
|
||||
if (!_remorse) _remorse = remorseComponent.createObject(shelfView)
|
||||
fadeAnimation.restart()
|
||||
//% "Deleting all books"
|
||||
_remorse.execute(qsTrId("shelf-view-about-to-delete-all"),
|
||||
doDeleteAll, _remorseTimeout)
|
||||
} else if (_remorse) {
|
||||
fadeAnimation.stop()
|
||||
_remorse.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: remorseComponent
|
||||
RemorsePopup {
|
||||
onCanceled: {
|
||||
shelfView.cancelDeleteAll()
|
||||
shelf.cancelAllDeleteRequests()
|
||||
fadeAnimation.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: dragItem
|
||||
onAnimatingChanged: if (!dragItem.animating && !dragArea.pressed) dragArea.finishDrag()
|
||||
}
|
||||
|
||||
BooksStorageHeader {
|
||||
id: storageHeader
|
||||
removable: removableStorage
|
||||
count: shelfModel.count
|
||||
showCount: !_loading
|
||||
}
|
||||
|
||||
SilicaGridView {
|
||||
id: grid
|
||||
anchors {
|
||||
top: singleStorage ? parent.top : storageHeader.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
leftMargin: Math.floor((shelfView.width - _cellsPerRow * shelfView.cellWidth)/_cellsPerRow/2)
|
||||
}
|
||||
model: shelfModel
|
||||
interactive: !dragInProgress
|
||||
clip: true
|
||||
opacity: (!_loading && _haveBooks) ? 1 : 0
|
||||
visible: opacity > 0
|
||||
cellWidth: shelfView.cellWidth
|
||||
cellHeight: shelfView.cellHeight
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
delegate: BooksShelfItem {
|
||||
editMode: shelfView.editMode
|
||||
dropped: dragItem.dropShelfIndex >= 0 &&
|
||||
dragItem.dropShelfIndex === shelfView.shelfIndex &&
|
||||
dragItem.dropItemIndex >= 0 &&
|
||||
dragItem.dropItemIndex === model.index
|
||||
dragged: dragItem.shelfIndex === shelfView.shelfIndex &&
|
||||
dragArea.draggedItemIndex === model.index
|
||||
visible: !model.dummy && !dragged && !dropped
|
||||
pressed: model.accessible && (model.index === dragArea.pressedItemIndex) && (model.index !== dragArea.pressedDeleteItemIndex)
|
||||
deleting: model.deleteRequested
|
||||
deletingAll: shelfView.deleteAllRequest
|
||||
deleteAllOpacity: grid.itemOpacity
|
||||
width: shelfView.cellWidth
|
||||
height: shelfView.cellHeight
|
||||
book: model.book
|
||||
name: model.name
|
||||
copyingIn: model.copyingIn
|
||||
copyingOut: model.copyingOut
|
||||
remorseTimeout: _remorseTimeout
|
||||
onScalingChanged: updateLastPressedItemScalingIndex()
|
||||
onPressedChanged: updateLastPressedItemScalingIndex()
|
||||
onDeleteMe: shelfView.shelf.remove(model.index)
|
||||
function updateLastPressedItemScalingIndex() {
|
||||
if (pressed && scaling) {
|
||||
dragArea.lastPressedItemScalingIndex = model.index
|
||||
} else if (dragArea.lastPressedItemScalingIndex === model.index) {
|
||||
dragArea.lastPressedItemScalingIndex = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property real itemOpacity: 1
|
||||
|
||||
moveDisplaced: Transition {
|
||||
SmoothedAnimation { properties: "x,y"; duration: 150 }
|
||||
}
|
||||
|
||||
removeDisplaced: Transition {
|
||||
SmoothedAnimation { properties: "x,y"; duration: 150 }
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: fadeAnimation
|
||||
target: grid
|
||||
property: "itemOpacity"
|
||||
from: 1
|
||||
to: 0
|
||||
duration: _remorseTimeout
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
BooksDragArea {
|
||||
id: dragArea
|
||||
dragParent: storageView
|
||||
gridView: grid
|
||||
onDeleteItemAt: {
|
||||
if (!shelfView.deleteAllRequest) {
|
||||
shelfView.shelf.setDeleteRequested(index, true);
|
||||
}
|
||||
}
|
||||
onDropItem: shelfView.dropItem(mouseX, mouseY)
|
||||
}
|
||||
|
||||
Behavior on y { SpringAnimation {} }
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
VerticalScrollDecorator {}
|
||||
}
|
||||
|
||||
ViewPlaceholder {
|
||||
//% "No books"
|
||||
text: qsTrId("shelf-view-no-books")
|
||||
enabled: !_loading && !_haveBooks
|
||||
PulleyAnimationHint {
|
||||
id: pulleyAnimationHint
|
||||
flickable: storageView
|
||||
anchors.fill: parent
|
||||
enabled: parent.enabled && !editMode
|
||||
}
|
||||
}
|
||||
|
||||
property Item _busyIndicator
|
||||
|
||||
Component {
|
||||
id: busyIndicatorComponent
|
||||
BusyIndicator {
|
||||
visible: opacity > 0
|
||||
anchors.centerIn: parent
|
||||
size: BusyIndicatorSize.Large
|
||||
running: _loading && !longStartTimer.running
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: longStartTimer
|
||||
interval: 500
|
||||
running: true
|
||||
onTriggered: {
|
||||
if (shelf.loading) {
|
||||
console.log(shelfModel.path, "startup is taking too long")
|
||||
startAnimationTimer.start()
|
||||
if (!_busyIndicator) _busyIndicator = busyIndicatorComponent.createObject(shelfView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: startAnimationTimer
|
||||
interval: 2000
|
||||
}
|
||||
}
|
125
app/qml/BooksStorageHeader.qml
Normal file
125
app/qml/BooksStorageHeader.qml
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
Column {
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
topMargin: Theme.paddingMedium
|
||||
}
|
||||
spacing: 0
|
||||
visible: opacity > 0
|
||||
opacity: singleStorage ? 0 : 1
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
|
||||
property bool removable
|
||||
property int count
|
||||
property bool showCount: true
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: Math.max(left.height, right.height)
|
||||
Row {
|
||||
id: left
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
spacing: 0
|
||||
Item {
|
||||
width: Theme.paddingMedium
|
||||
height: parent.height
|
||||
}
|
||||
BooksSDCardIcon {
|
||||
visible: removableStorage
|
||||
anchors.bottom: parent.bottom
|
||||
height: storageLabel.height*3/4
|
||||
}
|
||||
Item {
|
||||
visible: removableStorage
|
||||
width: Theme.paddingMedium
|
||||
height: parent.height
|
||||
}
|
||||
Label {
|
||||
id: storageLabel
|
||||
anchors.bottom: parent.bottom
|
||||
color: Theme.highlightColor
|
||||
text: removable ?
|
||||
//% "Memory card"
|
||||
qsTrId("storage-removable") :
|
||||
//% "Internal storage"
|
||||
qsTrId("storage-internal")
|
||||
}
|
||||
}
|
||||
Label {
|
||||
id: right
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
rightMargin: Theme.paddingMedium
|
||||
}
|
||||
//% "%0 book(s)"
|
||||
text: qsTrId("storage-book-count",count).arg(count)
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
color: Theme.highlightColor
|
||||
opacity: (showCount && count > 0) ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
height: Theme.paddingSmall
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: Theme.secondaryHighlightColor
|
||||
height: 1
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: Theme.highlightColor
|
||||
height: 1
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
}
|
||||
}
|
247
app/qml/BooksStorageView.qml
Normal file
247
app/qml/BooksStorageView.qml
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import harbour.books 1.0
|
||||
|
||||
SilicaFlickable {
|
||||
id: storageView
|
||||
interactive: !dragInProgress
|
||||
|
||||
property variant settings
|
||||
property bool editMode: false
|
||||
|
||||
signal openBook(var book)
|
||||
|
||||
property real _cellWidth: calculateCellWidth()
|
||||
property real _cellHeight: _cellWidth*8/5
|
||||
property var draggedItem
|
||||
property var currentShelf
|
||||
property var currentShelfView
|
||||
property int currentShelfIndex: storageListWatcher.currentIndex
|
||||
readonly property bool dragInProgress: draggedItem ? true : false
|
||||
readonly property real maxContentY: currentShelfView ? Math.max(0, currentShelfView.contentHeight - currentShelfView.height) : 0
|
||||
readonly property real verticalScrollThreshold: _cellHeight/2
|
||||
readonly property real horizontalScrollThreshold: _cellWidth/2
|
||||
|
||||
readonly property real _minGridCellWidth: 10*Theme.paddingMedium
|
||||
|
||||
// Books in the library shouldn't be too small or too big.
|
||||
// At least 3 (or 5 in landscape) should fit in the horizontal direction.
|
||||
// The width shouldn't be smaller than 10*Theme.paddingMedium or 0.88 inch
|
||||
function calculateCellWidth() {
|
||||
var result = 0
|
||||
if (width > 0) {
|
||||
// At least 3 books in portrait, 5 in landscape
|
||||
var n = (height > width) ? 4 : 6
|
||||
var cellSize = width/n
|
||||
while (cellSize > _minGridCellWidth && (cellSize/PointsPerInch) > 0.88 && n < 11) {
|
||||
cellSize = width/(++n)
|
||||
}
|
||||
result = Math.floor(width/(n-1))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
PullDownMenu {
|
||||
MenuItem {
|
||||
//% "Scan downloads"
|
||||
text: qsTrId("storage-view-scan-downloads")
|
||||
visible: !editMode
|
||||
onClicked: pageStack.push(importComponent)
|
||||
}
|
||||
MenuItem {
|
||||
//% "Delete all books"
|
||||
text: qsTrId("storage-view-delete-everything")
|
||||
visible: editMode
|
||||
enabled: currentShelf && (currentShelf.count > 0)
|
||||
onClicked: storageModel.setDeleteAllRequest(storageListWatcher.currentIndex, true)
|
||||
}
|
||||
}
|
||||
|
||||
onEditModeChanged: {
|
||||
storageModel.cancelDeleteAllRequests()
|
||||
dragScrollAnimation.stop()
|
||||
}
|
||||
|
||||
Component {
|
||||
id: importComponent
|
||||
BooksImport {
|
||||
destination: currentShelf ? currentShelf.path : ""
|
||||
onAccepted: {
|
||||
var count = selectedCount
|
||||
for (var i=0; i<count; i++) {
|
||||
currentShelf.importBook(selectedBook(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SystemState {
|
||||
id: globalSystemState
|
||||
onLockModeChanged: if (lockMode == "locked") editMode = false
|
||||
}
|
||||
|
||||
BookStorage {
|
||||
id: storageModel
|
||||
// Show the contents of SD-card and let use know that he can switch
|
||||
// between the internal memory and the removable storage by swiping
|
||||
// the list horizontally
|
||||
onNewStorage: storageList.scrollToPage(index)
|
||||
}
|
||||
|
||||
ListWatcher {
|
||||
id: storageListWatcher
|
||||
listView: storageList
|
||||
}
|
||||
|
||||
SilicaListView {
|
||||
id: storageList
|
||||
anchors.fill: parent
|
||||
model: storageModel
|
||||
flickDeceleration: maximumFlickVelocity
|
||||
orientation: ListView.Horizontal
|
||||
snapMode: ListView.SnapOneItem
|
||||
spacing: Theme.paddingMedium
|
||||
interactive: !dragInProgress && !dragScrollAnimation.running
|
||||
|
||||
readonly property real maxContentX: Math.max(0, contentWidth - width)
|
||||
|
||||
onMaxContentXChanged: {
|
||||
// SD-card can be removed while scroll animation is still active
|
||||
if (dragScrollAnimation.running && dragScrollAnimation.to > maxContentX) {
|
||||
dragScrollAnimation.to = maxContentX
|
||||
dragScrollAnimation.restart()
|
||||
}
|
||||
}
|
||||
|
||||
delegate: BooksShelfView {
|
||||
width: storageList.width
|
||||
height: storageList.height
|
||||
cellWidth: storageView._cellWidth
|
||||
cellHeight: storageView._cellHeight
|
||||
settings: storageView.settings
|
||||
singleStorage: storageModel.count < 2
|
||||
editMode: storageView.editMode
|
||||
deleteAllRequest: model.deleteAllRequest
|
||||
device: model.device
|
||||
removableStorage: model.removable
|
||||
shelfIndex: model.index
|
||||
onStartEditing: storageView.editMode = true
|
||||
onStopEditing: storageView.editMode = false
|
||||
onScrollLeft: storageList.scrollOnePageLeft()
|
||||
onScrollRight: storageList.scrollOnePageRight()
|
||||
onCancelDeleteAll: storageModel.cancelDeleteAllRequests()
|
||||
onDropItem: storageView.dropItem()
|
||||
|
||||
property bool current: model.index === currentShelfIndex
|
||||
Component.onCompleted: updateCurrentShelf()
|
||||
onCurrentChanged: updateCurrentShelf()
|
||||
function updateCurrentShelf() {
|
||||
if (current) {
|
||||
storageView.currentShelf = shelf
|
||||
storageView.currentShelfView = view
|
||||
} else {
|
||||
// no need for dummy item anymore
|
||||
shelf.hasDummyItem = false
|
||||
}
|
||||
}
|
||||
onOpenBook: storageView.openBook(book)
|
||||
}
|
||||
|
||||
function scrollOnePageLeft() {
|
||||
if (contentX > 0) {
|
||||
dragScrollAnimation.from = contentX
|
||||
dragScrollAnimation.to = Math.max(0, contentX - width - spacing)
|
||||
dragScrollAnimation.start()
|
||||
}
|
||||
}
|
||||
|
||||
function scrollOnePageRight() {
|
||||
if (contentX < maxContentX) {
|
||||
dragScrollAnimation.from = contentX
|
||||
dragScrollAnimation.to = Math.min(maxContentX, contentX + width + spacing)
|
||||
dragScrollAnimation.start()
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToPage(index) {
|
||||
dragScrollAnimation.from = contentX
|
||||
dragScrollAnimation.to = (width + spacing) * index
|
||||
dragScrollAnimation.start()
|
||||
}
|
||||
}
|
||||
|
||||
function dropItem() {
|
||||
if (draggedItem && dragItem.shelfIndex !== currentShelfIndex && currentShelf) {
|
||||
var targetIndex = currentShelf.dummyItemIndex
|
||||
if (targetIndex >= 0 && currentShelf.drop(draggedItem)) {
|
||||
console.log("drop accepted")
|
||||
// Update coordinates of the drag item to make it move toward the drop target
|
||||
var cellsPerRow = Math.floor(currentShelfView.width/_cellWidth)
|
||||
var delta = currentShelfView.mapToItem(storageView,0,0)
|
||||
var x = _cellWidth * (targetIndex % cellsPerRow) - currentShelfView.contentX
|
||||
var y = _cellHeight * Math.floor(targetIndex / cellsPerRow) - currentShelfView.contentY
|
||||
dragItem.x = x + delta.x
|
||||
dragItem.y = y + delta.y
|
||||
// This hides the target item until the grag item makes it to the destination:
|
||||
dragItem.dropShelfIndex = currentShelfIndex
|
||||
dragItem.dropItemIndex = targetIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BooksShelfItem {
|
||||
id: dragItem
|
||||
visible: false
|
||||
width: storageView._cellWidth
|
||||
height: storageView._cellHeight
|
||||
pressed: false
|
||||
editMode: false
|
||||
scaledDown: false
|
||||
scaleAnimationEnabled: false
|
||||
synchronous: true
|
||||
book: draggedItem ? draggedItem.book : null
|
||||
name: draggedItem ? draggedItem.name : ""
|
||||
property int shelfIndex: -1
|
||||
property int dropShelfIndex: -1
|
||||
property int dropItemIndex: -1
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: dragScrollAnimation
|
||||
target: storageList
|
||||
property: "contentX"
|
||||
duration: 500
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
63
app/qml/BooksTitleText.qml
Normal file
63
app/qml/BooksTitleText.qml
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright (C) 2015 Jolla Ltd.
|
||||
Contact: Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of 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 the 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 HOLDERS 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
Text {
|
||||
color: Theme.primaryColor
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
wrapMode: Text.Wrap
|
||||
onTextChanged: fitText()
|
||||
onWidthChanged: fitText()
|
||||
onHeightChanged: fitText()
|
||||
onPaintedHeightChanged: fitText()
|
||||
property bool _fittingText: false
|
||||
|
||||
function fitText() {
|
||||
if (!_fittingText) {
|
||||
_fittingText = true
|
||||
font.pixelSize = Theme.fontSizeSmall
|
||||
maximumLineCount = 100000
|
||||
elide = Text.ElideNone
|
||||
if (width > 0 && height > 0 && paintedHeight > height) {
|
||||
font.pixelSize = Theme.fontSizeTiny
|
||||
if (paintedHeight > height && lineHeight > 0) {
|
||||
maximumLineCount = height/lineHeight
|
||||
elide = Text.ElideRight
|
||||
}
|
||||
}
|
||||
_fittingText = false
|
||||
}
|
||||
}
|
||||
}
|
33
app/qml/images/close-x.svg
Normal file
33
app/qml/images/close-x.svg
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="100"
|
||||
height="100"
|
||||
viewBox="0 0 100 100"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="close-x.svg"><metadata
|
||||
id="metadata3074"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs3072" /><g
|
||||
id="graphic-close-app"
|
||||
transform="translate(0,-8)"><path
|
||||
style="fill:#ffffff;stroke:none"
|
||||
d="M 50,0 C 22.385763,0 0,22.385763 0,50 0,77.614238 22.385763,100 50,100 77.614237,100 100,77.614238 100,50 100,22.385763 77.614237,0 50,0 z M 28.84375,23.90625 44.6875,39.75 c 5.653,5.653 5.652,14.847 0,20.5 L 28.84375,76.09375 c -1.56467,1.257409 -3.594505,1.303267 -4.9375,0 -1.367,-1.367 -1.367,-3.5715 0,-4.9375 L 39.75,55.3125 c 2.924,-2.925 2.924,-7.701 0,-10.625 L 23.90625,28.84375 c -1.367,-1.367 -1.367,-3.5705 0,-4.9375 1.565153,-1.257526 3.594022,-1.302845 4.9375,0 z m 47.25,0 c 1.367,1.367 1.367,3.5705 0,4.9375 L 62.375,42.5625 c -4.094,4.094 -4.095,10.779 0,14.875 l 13.71875,13.71875 c 1.366,1.367 1.367,3.5705 0,4.9375 -1.566108,1.257128 -3.593266,1.302721 -4.9375,0 L 57.4375,62.375 c -6.822,-6.825 -6.823,-17.927 0,-24.75 L 71.15625,23.90625 c 1.564445,-1.258008 3.595058,-1.302741 4.9375,0 z"
|
||||
transform="translate(0,8)"
|
||||
id="circle3060"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ssssscscccccsscccsscccccscc" /></g></svg>
|
After Width: | Height: | Size: 2 KiB |
97
app/qml/images/cover-image.svg
Normal file
97
app/qml/images/cover-image.svg
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="86px"
|
||||
height="86px"
|
||||
viewBox="0 0 86 86"
|
||||
enable-background="new 0 0 86 86"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="cover-image.svg"><defs
|
||||
id="defs12"><linearGradient
|
||||
y2="18.8514"
|
||||
x2="6.7619"
|
||||
y1="91.3279"
|
||||
x1="79.2383"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3843"><stop
|
||||
id="stop3845"
|
||||
style="stop-color:#f5d9a8;stop-opacity:1;"
|
||||
offset="0" /><stop
|
||||
id="stop3847"
|
||||
style="stop-color:#cc9933;stop-opacity:1;"
|
||||
offset="1" /></linearGradient><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3843"
|
||||
id="linearGradient3833"
|
||||
x1="26.594183"
|
||||
y1="24.500792"
|
||||
x2="3.6175976"
|
||||
y2="4.4139266"
|
||||
gradientUnits="userSpaceOnUse" /></defs><metadata
|
||||
id="metadata25"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><path
|
||||
sodipodi:type="arc"
|
||||
style="fill:url(#linearGradient3833);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path3825"
|
||||
sodipodi:cx="13.5"
|
||||
sodipodi:cy="13.1875"
|
||||
sodipodi:rx="10.5"
|
||||
sodipodi:ry="9.8125"
|
||||
d="m 24,13.1875 a 10.5,9.8125 0 1 1 -21,0 10.5,9.8125 0 1 1 21,0 z"
|
||||
transform="matrix(4.0952381,0,0,4.3821656,-12.285714,-14.789809)" /><g
|
||||
id="Layer_1"></g><path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 63.019685,23.201772 2.480315,0 0,47.568897 -35.610236,0 C 24.663386,70.770669 20.5,67.13878 20.5,61.735235 l 0,-41.190944 c 0,-2.923228 2.391733,-5.31496 5.314961,-5.31496 l 32.952755,0 0,40.836614 -28.877952,0 c -3.63189,0 -6.200788,1.948818 -6.200788,5.492126 l 0,0.177164 c 0,3.543308 2.568898,5.846458 6.200788,5.846458 l 33.129921,0 0,-44.379921 z m -4.251969,39.773621 -28.523622,0 c -0.797243,0 -1.505905,-0.442912 -1.505905,-1.328739 0,-0.708662 0.708662,-1.151576 1.505905,-1.151576 l 28.523622,0 0,2.480315 z"
|
||||
id="path4"
|
||||
style="fill:#cc0000;fill-opacity:1;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:4;stroke-linecap:square;stroke-miterlimit:3;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path2999"
|
||||
sodipodi:cx="43"
|
||||
sodipodi:cy="44.275425"
|
||||
sodipodi:rx="42.088985"
|
||||
sodipodi:ry="51.745762"
|
||||
d="m 85.088985,44.275425 a 42.088985,51.745762 0 1 1 -84.17797044,0 42.088985,51.745762 0 1 1 84.17797044,0 z" /><path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:4;stroke-linecap:square;stroke-miterlimit:3;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path3769"
|
||||
sodipodi:cx="22.684322"
|
||||
sodipodi:cy="17.491526"
|
||||
sodipodi:rx="12.298729"
|
||||
sodipodi:ry="12.207627"
|
||||
d="M 34.983051,17.491526 A 12.298729,12.207627 0 1 1 22.792077,5.2843669 L 22.684322,17.491526 z"
|
||||
sodipodi:start="0"
|
||||
sodipodi:end="4.7211505" /><path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:4;stroke-linecap:square;stroke-miterlimit:3;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path3799"
|
||||
sodipodi:cx="3"
|
||||
sodipodi:cy="5"
|
||||
sodipodi:rx="80.07618"
|
||||
sodipodi:ry="1.096934"
|
||||
d="M 83.07618,5 A 80.07618,1.096934 0 1 1 3.70158,3.9031081 L 3,5 z"
|
||||
sodipodi:start="0"
|
||||
sodipodi:end="4.7211505" /><path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:4;stroke-linecap:square;stroke-miterlimit:3;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path3801"
|
||||
sodipodi:cx="84.75"
|
||||
sodipodi:cy="18.5"
|
||||
sodipodi:rx="18.75"
|
||||
sodipodi:ry="18.75"
|
||||
d="m 103.5,18.5 a 18.75,18.75 0 1 1 -37.5,0 18.75,18.75 0 1 1 37.5,0 z" /></svg>
|
After Width: | Height: | Size: 4.6 KiB |
BIN
app/qml/images/default-cover.jpg
Normal file
BIN
app/qml/images/default-cover.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
50
app/qml/images/sdcard.svg
Normal file
50
app/qml/images/sdcard.svg
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="80.000008"
|
||||
height="60.001255"
|
||||
id="svg5195"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="sdcard.svg">
|
||||
<metadata
|
||||
id="metadata5200">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-654.28125,-625.21875)">
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;stroke-opacity:1;stroke-dasharray:none"
|
||||
inkscape:connector-curvature="0"
|
||||
stroke-miterlimit="3"
|
||||
d="m 731.87523,627.52841 0.40612,0.63624 0,46.62096 -0.56399,1.1596 -1.12305,0 -22.24234,0 -8.44016,7.27461 -7.68553,-0.0623 -0.47563,-0.29767 -0.27803,-0.58382 0,-2.04206 -5.07405,0 -3.94305,2.98613 -20.5052,0 -5.20258,0 -0.39718,-0.13334 -0.0694,-0.52447 0,-54.77808 0.0144,-0.0187 0.25471,-0.33121 0.25818,-0.0615 1.2803,0 46.21305,0 4.17044,0 22.66932,-0.15291 z"
|
||||
id="path308-7-4"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccccccc" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none"
|
||||
d="m 730.15625,628.22001 -22.0625,0.15625 -4.0625,0 -45,0 -1.25,0 -0.25,0.0625 -0.25,0.3125 0,52.84375 0.0625,0.5 0.40625,0.125 5.0625,0 19.96875,0 3.8125,-2.875 4.9375,0 0,1.96875 0.28125,0.5625 0.46875,0.28125 7.46875,0.0625 8.21875,-7 21.65625,0 1.09375,0 0.5625,-1.125 0,-44.96875 -0.40625,-0.59375 -0.71875,-0.3125 z m -61.125,10.28125 c 1.82713,-0.0787 3.62648,0.47484 4.21875,1.53125 1.48537,-2.34183 9.15625,-2.10021 9.15625,2.25 l 0,19.03125 -4.125,0 0,-17.15625 c -0.56407,-1.32417 -2.82364,-1.29592 -3.3125,-0.125 l 0,17.4375 -1.5,0 -0.46875,-0.0625 -1.46875,0 0,-17.4375 c -0.47005,-1.16523 -2.65468,-1.16223 -3.21875,0.15625 l 0,17.125 -4.03125,0 0,-19.03125 c 0,-2.46854 2.40084,-3.61757 4.75,-3.71875 z m 48.75,0 c 3.4878,0.0824 6.57521,3.26298 6.5,7.09375 0.002,0.0979 0.002,0.21668 0,0.3125 -0.0733,3.83086 -3.0122,6.86173 -6.5,6.78125 -3.4878,-0.0805 -6.54396,-3.26673 -6.46875,-7.09375 -0.002,-0.0977 -0.002,-0.21285 0,-0.3125 0.0733,-3.82899 2.97907,-6.86174 6.46875,-6.78125 z M 685.75,638.65751 c 1.25233,0 2.25,1.03607 2.25,2.3125 0,1.27641 -0.99767,2.3125 -2.25,2.3125 -1.25233,0 -2.28125,-1.03609 -2.28125,-2.3125 0,-1.27643 1.02892,-2.3125 2.28125,-2.3125 z m 8.71875,0.125 2.9375,0 c 1.2541,0 2.28125,0.89041 2.28125,2 0,1.10767 -1.02715,2.03125 -2.28125,2.03125 l -2.21875,0 c -1.01344,0.25296 -1.82345,0.98505 -2.15625,1.9375 -0.54338,1.55419 0.34988,3.22682 1.96875,3.75 l 2.40625,0 0.21875,0.0312 c 0.17298,0.0153 0.36579,0.0439 0.53125,0.0937 1.18078,0.36794 1.79053,1.51231 1.375,2.5625 -0.31776,0.79913 -1.16797,1.34375 -2.125,1.34375 l -2.4375,-0.0312 c -3.34114,-0.19164 -6.06943,-2.69748 -6.5,-5.96875 -0.4945,-3.76 2.18316,-7.19883 6,-7.6875 l 0,-0.0625 z m 10.09375,0 c 0.3134,-0.0123 0.61622,0.0366 0.9375,0.0937 0.62987,-0.11307 1.28578,-0.0985 1.90625,0.0625 2.53641,0.65157 4.07982,3.36426 3.46875,6.0625 l -3.78125,0 -0.0312,-1.09375 c 0.002,-0.0537 0.002,-0.13193 0,-0.1875 -0.0526,-0.82788 -0.80872,-1.45033 -1.71875,-1.40625 -0.91003,0.046 -1.61139,0.76203 -1.5625,1.59375 l 0,4.8125 0,3.125 0,0.6875 -3.78125,0 0,-8.71875 0,-0.34375 c 0.0113,-0.16481 0.0362,-0.30778 0.0625,-0.46875 0.37675,-2.39285 2.30619,-4.1329 4.5,-4.21875 z m 13.21875,3.8125 c -1.61889,0 -2.875,1.35016 -2.875,3 0,1.6502 1.25611,3 2.875,3 1.61889,0 3,-1.3498 3,-3 0,-1.64984 -1.38111,-3 -3,-3 z m -31.9375,1.0625 c 1.25222,0.0632 2.21642,1.12993 2.15625,2.40625 l 0,7.125 -4.53125,0 0,-7.125 c -0.004,-0.0751 -0.004,-0.14402 0,-0.21875 0.062,-1.27632 1.12466,-2.25075 2.375,-2.1875 z m 15.78125,9.875 c 1.77351,0.002 2.96875,0.0312 2.96875,0.0312 l -0.84375,2.4375 c 0,0 -6.58341,0.0146 -8.28125,0.0625 -1.56246,0.0422 -3.8125,-0.011 -3.8125,0.84375 0,0.66881 3.34677,1.44616 5.1875,2 2.71879,0.82404 5.00792,2.08047 4.40625,4.75 -0.84798,3.77911 -5.48319,3.5625 -11.09375,3.5625 -3.93905,0 -7.625,-0.25 -7.625,-0.25 l 1.53125,-4.28125 c 0,0 3.25363,0.39592 7.125,0.46875 2.49881,0.0479 3.34375,0.002 3.34375,-0.59375 0,-0.73206 -2.29471,-1.15725 -3.75,-1.71875 -1.52486,-0.596 -4.05245,-1.90761 -3.84375,-3.8125 0.1523,-1.46796 1.43869,-2.9988 8.21875,-3.34375 2.35027,-0.12074 4.69523,-0.15817 6.46875,-0.15625 z m 5.375,0.0312 c 2.11712,-0.006 2.87095,0.0184 4.78125,0.0625 0.47757,0.0153 1.28849,0.10627 2.28125,0.25 l -4.09375,2.5625 c -0.65243,-0.16865 -1.38653,-0.30027 -2.1875,-0.375 -0.8837,-0.0843 -1.10418,-0.0433 -1.625,-0.0625 L 707,653.56376 z m 10.34375,0.875 c 0.48134,0.13223 1.15307,0.38294 1.625,0.59375 l -6.90625,2.3125 c -0.0395,-0.0268 -0.0874,-0.0376 -0.125,-0.0625 -0.13726,-0.0958 -0.39328,-0.31235 -0.5625,-0.40625 l 5.96875,-2.4375 z m 3.34375,1.3125 c 1.29923,0.65157 2.40092,1.47148 2.96875,2.53125 0.50578,0.93328 0.39913,1.90088 -0.1875,2.84375 -4.67234,5.91493 -16.82844,5.86511 -21.21875,6.0625 l 1.90625,-5.46875 c 1.16009,-0.0441 2.83971,-0.20695 3.84375,-0.40625 1.00216,-0.20314 1.88983,-0.46505 2.625,-0.78125 0.722,-0.31429 1.28773,-0.68498 1.65625,-1.0625 0.36287,-0.37178 0.50143,-0.75956 0.4375,-1.15625 -0.015,-0.0974 -0.0486,-0.18544 -0.0937,-0.28125 -0.0263,-0.0613 -0.0505,-0.1281 -0.0937,-0.1875 l 8.15625,-2.09375 z"
|
||||
id="path308-7"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
id="g5062"
|
||||
transform="matrix(1.8802169,0,0,1.9163882,639.48533,-1272.1248)" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.9 KiB |
511
app/src/BooksBook.cpp
Normal file
511
app/src/BooksBook.cpp
Normal file
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksBook.h"
|
||||
#include "BooksDefs.h"
|
||||
#include "BooksTask.h"
|
||||
#include "BooksTextView.h"
|
||||
#include "BooksTextStyle.h"
|
||||
#include "BooksPaintContext.h"
|
||||
|
||||
#include "HarbourJson.h"
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include "ZLImage.h"
|
||||
#include "image/ZLQtImageManager.h"
|
||||
#include "bookmodel/BookModel.h"
|
||||
#include "library/Author.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QDirIterator>
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
|
||||
#define BOOK_STATE_POSITION "position"
|
||||
#define BOOK_COVER_SUFFIX ".cover."
|
||||
|
||||
// ==========================================================================
|
||||
// BooksBook::CoverContext
|
||||
// ==========================================================================
|
||||
class BooksBook::CoverPaintContext : public BooksPaintContext {
|
||||
public:
|
||||
CoverPaintContext();
|
||||
|
||||
void drawImage(int x, int y, const ZLImageData& image);
|
||||
void drawImage(int x, int y, const ZLImageData& image, int width, int height, ScalingType type);
|
||||
void handleImage(const ZLImageData& image);
|
||||
bool gotIt() const;
|
||||
|
||||
public:
|
||||
static QSize gMaxScreenSize;
|
||||
static bool gMaxScreenSizeKnown;
|
||||
|
||||
QImage iImage;
|
||||
};
|
||||
|
||||
QSize BooksBook::CoverPaintContext::gMaxScreenSize(480,640);
|
||||
bool BooksBook::CoverPaintContext::gMaxScreenSizeKnown = false;
|
||||
|
||||
BooksBook::CoverPaintContext::CoverPaintContext()
|
||||
{
|
||||
if (!gMaxScreenSizeKnown) {
|
||||
QList<QScreen*> screens = qGuiApp->screens();
|
||||
const int n = screens.count();
|
||||
for (int i=0; i<n; i++) {
|
||||
QSize s = screens.at(i)->size();
|
||||
gMaxScreenSize.setWidth(qMax(s.width(), gMaxScreenSize.width()));
|
||||
gMaxScreenSize.setHeight(qMax(s.width(), gMaxScreenSize.height()));
|
||||
}
|
||||
}
|
||||
|
||||
setWidth(gMaxScreenSize.width());
|
||||
setHeight(gMaxScreenSize.height());
|
||||
}
|
||||
|
||||
void BooksBook::CoverPaintContext::drawImage(int x, int y, const ZLImageData& image)
|
||||
{
|
||||
handleImage(image);
|
||||
}
|
||||
|
||||
void BooksBook::CoverPaintContext::drawImage(int x, int y, const ZLImageData& image,
|
||||
int width, int height, ScalingType type)
|
||||
{
|
||||
handleImage(image);
|
||||
}
|
||||
|
||||
void BooksBook::CoverPaintContext::handleImage(const ZLImageData& image)
|
||||
{
|
||||
const QImage* qImage = ((ZLQtImageData&)image).image();
|
||||
HDEBUG(image.width() << 'x' << image.height());
|
||||
if (qImage->height() > qImage->width() &&
|
||||
qImage->width() > iImage.width() &&
|
||||
qImage->height() > iImage.height()) {
|
||||
iImage = *qImage;
|
||||
}
|
||||
}
|
||||
|
||||
bool BooksBook::CoverPaintContext::gotIt() const
|
||||
{
|
||||
return iImage.width() >= 50 &&
|
||||
iImage.height() >= 80 &&
|
||||
iImage.height() > iImage.width();
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksBook::CoverTask
|
||||
// ==========================================================================
|
||||
|
||||
class BooksBook::CoverTask : public BooksTask
|
||||
{
|
||||
public:
|
||||
CoverTask(BooksStorage aStorage, shared_ptr<Book> aBook) :
|
||||
iStorage(aStorage), iBook(aBook), iCoverMissing(false) {}
|
||||
|
||||
bool hasImage() const;
|
||||
|
||||
public:
|
||||
BooksStorage iStorage;
|
||||
shared_ptr<Book> iBook;
|
||||
QImage iCoverImage;
|
||||
bool iCoverMissing;
|
||||
};
|
||||
|
||||
inline bool BooksBook::CoverTask::hasImage() const
|
||||
{
|
||||
return iCoverImage.width() > 0 && iCoverImage.height() > 0;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksBook::LoadCoverTask
|
||||
// ==========================================================================
|
||||
|
||||
class BooksBook::LoadCoverTask : public BooksBook::CoverTask
|
||||
{
|
||||
public:
|
||||
LoadCoverTask(BooksStorage aStorage, shared_ptr<Book> aBook,
|
||||
shared_ptr<FormatPlugin> aFormatPlugin) :
|
||||
BooksBook::CoverTask(aStorage, aBook),
|
||||
iFormatPlugin(aFormatPlugin) {}
|
||||
|
||||
virtual void performTask();
|
||||
|
||||
public:
|
||||
shared_ptr<FormatPlugin> iFormatPlugin;
|
||||
};
|
||||
|
||||
void BooksBook::LoadCoverTask::performTask()
|
||||
{
|
||||
if (!isCanceled()) {
|
||||
// Try to load cached (or custom) cover
|
||||
if (iStorage.isValid()) {
|
||||
QString coverPrefix(QString::fromStdString(
|
||||
iBook->file().name(false)) + BOOK_COVER_SUFFIX);
|
||||
QDirIterator it(iStorage.configDir());
|
||||
while (it.hasNext()) {
|
||||
QString path(it.next());
|
||||
if (it.fileName().startsWith(coverPrefix)) {
|
||||
if (QFile(path).size() == 0) {
|
||||
HDEBUG("no cover for" << iBook->title().c_str());
|
||||
iCoverMissing = true;
|
||||
return;
|
||||
} else if (iCoverImage.load(path)) {
|
||||
HDEBUG("loaded cover" << iCoverImage.width() << 'x' <<
|
||||
iCoverImage.height() << "for" <<
|
||||
iBook->title().c_str() << "from" <<
|
||||
qPrintable(path));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OK, fetch one from the book file
|
||||
shared_ptr<ZLImageData> imageData;
|
||||
shared_ptr<ZLImage> image = iFormatPlugin->coverImage(iBook->file());
|
||||
if (!image.isNull()) {
|
||||
imageData = ZLImageManager::Instance().imageData(*image);
|
||||
}
|
||||
if (!imageData.isNull()) {
|
||||
QImage* qImage = (QImage*)((ZLQtImageData&)*imageData).image();
|
||||
if (qImage) iCoverImage = *qImage;
|
||||
}
|
||||
}
|
||||
#if HARBOUR_DEBUG
|
||||
if (hasImage()) {
|
||||
HDEBUG("loaded cover" << iCoverImage.width() << 'x' <<
|
||||
iCoverImage.height() << "for" << iBook->title().c_str());
|
||||
} else if (isCanceled()) {
|
||||
HDEBUG("cancelled" << iBook->title().c_str());
|
||||
} else {
|
||||
HDEBUG("no cover found in" << iBook->title().c_str());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksBook::GuessCoverTask
|
||||
// ==========================================================================
|
||||
|
||||
class BooksBook::GuessCoverTask : public BooksBook::CoverTask
|
||||
{
|
||||
public:
|
||||
GuessCoverTask(BooksStorage aStorage, shared_ptr<Book> aBook) :
|
||||
BooksBook::CoverTask(aStorage, aBook) {}
|
||||
|
||||
virtual void performTask();
|
||||
};
|
||||
|
||||
void BooksBook::GuessCoverTask::performTask()
|
||||
{
|
||||
if (!isCanceled()) {
|
||||
BooksMargins margins;
|
||||
CoverPaintContext context;
|
||||
BookModel bookModel(iBook);
|
||||
shared_ptr<ZLTextModel> model(bookModel.bookTextModel());
|
||||
BooksTextView view(context, BooksTextStyle::defaults(), margins);
|
||||
view.setModel(model);
|
||||
view.rewind();
|
||||
if (!isCanceled()) {
|
||||
view.rewind();
|
||||
if (!isCanceled()) {
|
||||
view.paint();
|
||||
iCoverImage = context.iImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString coverPath;
|
||||
if (iStorage.isValid()) {
|
||||
coverPath = iStorage.configDir().path() + "/" +
|
||||
QString::fromStdString(iBook->file().name(false)) +
|
||||
BOOK_COVER_SUFFIX + "jpg";
|
||||
}
|
||||
|
||||
if (hasImage()) {
|
||||
HDEBUG("using image" << iCoverImage.width() << 'x' <<
|
||||
iCoverImage.width() << "as cover for" << iBook->title().c_str());
|
||||
|
||||
// Save the extracted image
|
||||
if (!coverPath.isEmpty() && iCoverImage.save(coverPath)) {
|
||||
HDEBUG("saved cover to" << qPrintable(coverPath));
|
||||
}
|
||||
} else if (isCanceled()) {
|
||||
HDEBUG("cancelled" << iBook->title().c_str());
|
||||
} else {
|
||||
HDEBUG("no cover for" << iBook->title().c_str());
|
||||
iCoverMissing = true;
|
||||
|
||||
// Create empty file. Guessing the cover image is an expensive task,
|
||||
// we don't want to do it every time the application is started.
|
||||
if (!coverPath.isEmpty() &&
|
||||
// Check if the book file still exists - the failure could've
|
||||
// been caused by the SD-card removal.
|
||||
QFile::exists(QString::fromStdString(iBook->file().path()))) {
|
||||
QFile(coverPath).open(QIODevice::WriteOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksBook
|
||||
// ==========================================================================
|
||||
|
||||
// This constructor isn't really used, but is required by qmlRegisterType
|
||||
BooksBook::BooksBook(QObject* aParent) :
|
||||
QObject(aParent),
|
||||
iRef(-1)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
BooksBook::BooksBook(const BooksStorage& aStorage, shared_ptr<Book> aBook) :
|
||||
QObject(NULL),
|
||||
iRef(1),
|
||||
iStorage(aStorage),
|
||||
iBook(aBook),
|
||||
iTaskQueue(BooksTaskQueue::instance())
|
||||
{
|
||||
init();
|
||||
HASSERT(!iBook.isNull());
|
||||
iTitle = QString::fromStdString(iBook->title());
|
||||
iPath = QString::fromStdString(iBook->file().path());
|
||||
iFileName = QString::fromStdString(iBook->file().name(false));
|
||||
iFormatPlugin = PluginCollection::Instance().plugin(*iBook);
|
||||
AuthorList authors(iBook->authors());
|
||||
const int n = authors.size();
|
||||
for (int i=0; i<n; i++) {
|
||||
if (i > 0) iAuthors += ", ";
|
||||
iAuthors += QString::fromStdString(authors[i]->name());
|
||||
}
|
||||
if (iStorage.isValid()) {
|
||||
iStateFilePath = iStorage.configDir().path() + "/" +
|
||||
iFileName + BOOKS_STATE_FILE_SUFFIX;
|
||||
// Load the state
|
||||
QVariantMap state;
|
||||
if (HarbourJson::load(iStateFilePath, state)) {
|
||||
iLastPos = BooksPos::fromVariant(state.value(BOOK_STATE_POSITION));
|
||||
}
|
||||
}
|
||||
// Refcounted BooksBook objects are managed by C++ code
|
||||
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
void BooksBook::init()
|
||||
{
|
||||
iCoverTask = NULL;
|
||||
iCoverTasksDone = false;
|
||||
iCopyingOut = false;
|
||||
iSaveTimer = NULL;
|
||||
}
|
||||
|
||||
BooksBook::~BooksBook()
|
||||
{
|
||||
HDEBUG(qPrintable(iPath));
|
||||
HASSERT(!iRef.load());
|
||||
if (iCoverTask) iCoverTask->release(this);
|
||||
}
|
||||
|
||||
BooksItem* BooksBook::retain()
|
||||
{
|
||||
if (iRef.load() >= 0) {
|
||||
iRef.ref();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void BooksBook::release()
|
||||
{
|
||||
if (iRef.load() >= 0 && !iRef.deref()) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
QObject* BooksBook::object()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
BooksShelf* BooksBook::shelf()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BooksBook* BooksBook::book()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
QString BooksBook::name() const
|
||||
{
|
||||
return iTitle;
|
||||
}
|
||||
|
||||
QString BooksBook::fileName() const
|
||||
{
|
||||
return iFileName;
|
||||
}
|
||||
|
||||
void BooksBook::setLastPos(const BooksPos& aPos)
|
||||
{
|
||||
if (iLastPos != aPos) {
|
||||
iLastPos = aPos;
|
||||
// We only need save timer if we have the state file
|
||||
if (!iSaveTimer && iStorage.isValid()) {
|
||||
iSaveTimer = new BooksSaveTimer(this);
|
||||
connect(iSaveTimer, SIGNAL(save()), SLOT(saveState()));
|
||||
}
|
||||
if (iSaveTimer) iSaveTimer->requestSave();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBook::setCopyingOut(bool aValue)
|
||||
{
|
||||
if (iCopyingOut != aValue) {
|
||||
const bool wasAccessible = accessible();
|
||||
iCopyingOut = aValue;
|
||||
Q_EMIT copyingOutChanged();
|
||||
if (wasAccessible != accessible()) {
|
||||
Q_EMIT accessibleChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QImage BooksBook::coverImage()
|
||||
{
|
||||
return iCoverImage;
|
||||
}
|
||||
|
||||
bool BooksBook::hasCoverImage() const
|
||||
{
|
||||
return iCoverImage.width() > 0 && iCoverImage.height() > 0;
|
||||
}
|
||||
|
||||
void BooksBook::setCoverImage(QImage aImage)
|
||||
{
|
||||
if (iCoverImage != aImage) {
|
||||
iCoverImage = aImage;
|
||||
Q_EMIT coverImageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool BooksBook::requestCoverImage()
|
||||
{
|
||||
if (!iBook.isNull() && !iFormatPlugin.isNull() &&
|
||||
!iCoverTasksDone && !iCoverTask) {
|
||||
HDEBUG(iTitle);
|
||||
iCoverTask = new LoadCoverTask(iStorage, iBook, iFormatPlugin);
|
||||
connect(iCoverTask, SIGNAL(done()), SLOT(onLoadCoverTaskDone()));
|
||||
iTaskQueue->submit(iCoverTask);
|
||||
Q_EMIT loadingCoverChanged();
|
||||
}
|
||||
return iCoverTask != NULL;
|
||||
}
|
||||
|
||||
void BooksBook::cancelCoverRequest()
|
||||
{
|
||||
if (iCoverTask) {
|
||||
iCoverTask->release(this);
|
||||
iCoverTask = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool BooksBook::coverTaskDone()
|
||||
{
|
||||
HASSERT(sender() == iCoverTask);
|
||||
HASSERT(!iCoverTasksDone);
|
||||
HDEBUG(iTitle << iCoverTask->hasImage());
|
||||
const bool gotCover = iCoverTask->hasImage();
|
||||
if (gotCover) {
|
||||
iCoverImage = iCoverTask->iCoverImage;
|
||||
Q_EMIT coverImageChanged();
|
||||
}
|
||||
iCoverTask->release(this);
|
||||
iCoverTask = NULL;
|
||||
return gotCover;
|
||||
}
|
||||
|
||||
void BooksBook::onLoadCoverTaskDone()
|
||||
{
|
||||
HDEBUG(iTitle);
|
||||
const bool coverMissing = iCoverTask->iCoverMissing;
|
||||
if (coverTaskDone() || coverMissing) {
|
||||
iCoverTasksDone = true;
|
||||
Q_EMIT loadingCoverChanged();
|
||||
} else {
|
||||
iCoverTask = new GuessCoverTask(iStorage, iBook);
|
||||
connect(iCoverTask, SIGNAL(done()), SLOT(onGuessCoverTaskDone()));
|
||||
iTaskQueue->submit(iCoverTask);
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBook::onGuessCoverTaskDone()
|
||||
{
|
||||
HDEBUG(iTitle);
|
||||
coverTaskDone();
|
||||
iCoverTasksDone = true;
|
||||
Q_EMIT loadingCoverChanged();
|
||||
}
|
||||
|
||||
void BooksBook::saveState()
|
||||
{
|
||||
if (!iStateFilePath.isEmpty()) {
|
||||
QVariantMap state;
|
||||
HarbourJson::load(iStateFilePath, state);
|
||||
state.insert(BOOK_STATE_POSITION, iLastPos.toVariant());
|
||||
if (HarbourJson::save(iStateFilePath, state)) {
|
||||
HDEBUG("wrote" << iStateFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBook::deleteFiles()
|
||||
{
|
||||
if (iStorage.isValid()) {
|
||||
if (QFile::remove(iPath)) {
|
||||
HDEBUG("deleted" << qPrintable(iPath));
|
||||
} else {
|
||||
HWARN("failed to delete" << qPrintable(iPath));
|
||||
}
|
||||
QDirIterator it(iStorage.configDir());
|
||||
while (it.hasNext()) {
|
||||
QString path(it.next());
|
||||
if (it.fileName().startsWith(iFileName)) {
|
||||
if (QFile::remove(path)) {
|
||||
HDEBUG(qPrintable(path));
|
||||
} else {
|
||||
HWARN("failed to delete" << qPrintable(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
136
app/src/BooksBook.h
Normal file
136
app/src/BooksBook.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_BOOK_H
|
||||
#define BOOKS_BOOK_H
|
||||
|
||||
#include "BooksItem.h"
|
||||
#include "BooksPos.h"
|
||||
#include "BooksStorage.h"
|
||||
#include "BooksSaveTimer.h"
|
||||
#include "BooksTaskQueue.h"
|
||||
|
||||
#include "ZLImageManager.h"
|
||||
#include "formats/FormatPlugin.h"
|
||||
#include "library/Book.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QtQml>
|
||||
|
||||
class BooksBook : public QObject, public BooksItem
|
||||
{
|
||||
class CoverTask;
|
||||
class LoadCoverTask;
|
||||
class GuessCoverTask;
|
||||
class CoverPaintContext;
|
||||
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString path READ path CONSTANT)
|
||||
Q_PROPERTY(QString name READ title CONSTANT)
|
||||
Q_PROPERTY(QString title READ title CONSTANT)
|
||||
Q_PROPERTY(QString authors READ authors CONSTANT)
|
||||
Q_PROPERTY(BooksBook* book READ book CONSTANT)
|
||||
Q_PROPERTY(bool accessible READ accessible NOTIFY accessibleChanged)
|
||||
Q_PROPERTY(bool loadingCover READ loadingCover NOTIFY loadingCoverChanged)
|
||||
Q_PROPERTY(bool copyingOut READ copyingOut NOTIFY copyingOutChanged)
|
||||
|
||||
public:
|
||||
BooksBook(QObject* aParent = NULL);
|
||||
BooksBook(const BooksStorage& aStorage, shared_ptr<Book> aBook);
|
||||
~BooksBook();
|
||||
|
||||
QString path() const { return iPath; }
|
||||
QString title() const { return iTitle; }
|
||||
QString authors() const { return iAuthors; }
|
||||
BooksPos lastPos() const { return iLastPos; }
|
||||
void setLastPos(const BooksPos& aPos);
|
||||
shared_ptr<Book> bookRef() const { return iBook; }
|
||||
bool accessible() const { return !iCopyingOut; }
|
||||
bool copyingOut() const { return iCopyingOut; }
|
||||
bool loadingCover() const { return !iCoverTasksDone; }
|
||||
bool hasCoverImage() const;
|
||||
bool requestCoverImage();
|
||||
void cancelCoverRequest();
|
||||
void setCoverImage(QImage aImage);
|
||||
QImage coverImage();
|
||||
|
||||
void setCopyingOut(bool aValue);
|
||||
void deleteFiles();
|
||||
|
||||
// BooksListItem
|
||||
virtual BooksItem* retain();
|
||||
virtual void release();
|
||||
virtual QObject* object();
|
||||
virtual BooksShelf* shelf();
|
||||
virtual BooksBook* book();
|
||||
virtual QString name() const;
|
||||
virtual QString fileName() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void coverImageChanged();
|
||||
void loadingCoverChanged();
|
||||
void accessibleChanged();
|
||||
void copyingOutChanged();
|
||||
void movedAway();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onLoadCoverTaskDone();
|
||||
void onGuessCoverTaskDone();
|
||||
void saveState();
|
||||
|
||||
private:
|
||||
void init();
|
||||
bool coverTaskDone();
|
||||
|
||||
private:
|
||||
QAtomicInt iRef;
|
||||
BooksPos iLastPos;
|
||||
BooksStorage iStorage;
|
||||
shared_ptr<Book> iBook;
|
||||
QImage iCoverImage;
|
||||
shared_ptr<FormatPlugin> iFormatPlugin;
|
||||
shared_ptr<BooksTaskQueue> iTaskQueue;
|
||||
BooksSaveTimer* iSaveTimer;
|
||||
CoverTask* iCoverTask;
|
||||
bool iCoverTasksDone;
|
||||
bool iCopyingOut;
|
||||
QString iTitle;
|
||||
QString iAuthors;
|
||||
QString iFileName;
|
||||
QString iPath;
|
||||
QString iStateFilePath;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(BooksBook)
|
||||
|
||||
#endif // BOOKS_BOOK_H
|
543
app/src/BooksBookModel.cpp
Normal file
543
app/src/BooksBookModel.cpp
Normal file
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksBookModel.h"
|
||||
#include "BooksTextStyle.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include "ZLTextHyphenator.h"
|
||||
|
||||
// ==========================================================================
|
||||
// BooksBookModel::Data
|
||||
// ==========================================================================
|
||||
class BooksBookModel::Data {
|
||||
public:
|
||||
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:
|
||||
int iWidth;
|
||||
int iHeight;
|
||||
shared_ptr<BookModel> iBookModel;
|
||||
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.
|
||||
if (iPageMarks.count() > aPageCount) {
|
||||
it = qUpperBound(iPageMarks, aPagePos);
|
||||
page = (int)(it - iPageMarks.begin()) - 1;
|
||||
HDEBUG("using page" << page << "for" << aPagePos);
|
||||
} else {
|
||||
it = qLowerBound(iPageMarks, aNextPagePos);
|
||||
page = (int)(it - iPageMarks.begin());
|
||||
if (page > 0) page--;
|
||||
HDEBUG("using page" << page << "for" << aNextPagePos);
|
||||
}
|
||||
} else {
|
||||
page = it - iPageMarks.begin();
|
||||
HDEBUG("found" << aPagePos << "at page" << page);
|
||||
}
|
||||
}
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksBookModel::Task
|
||||
// ==========================================================================
|
||||
|
||||
class BooksBookModel::Task : public BooksTask
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Task(BooksBookModel* aReceiver, shared_ptr<Book> aBook,
|
||||
const BooksPos& aPagePos, const BooksPos& aNextPagePos,
|
||||
const BooksPos& aLastPos, int aPageCount);
|
||||
~Task();
|
||||
|
||||
void performTask();
|
||||
|
||||
Q_SIGNALS:
|
||||
void progress(int aProgress);
|
||||
|
||||
public:
|
||||
shared_ptr<Book> iBook;
|
||||
shared_ptr<ZLTextStyle> iTextStyle;
|
||||
BooksMargins iMargins;
|
||||
BooksPaintContext iPaint;
|
||||
BooksBookModel::Data* iData;
|
||||
BooksPos iPagePos;
|
||||
BooksPos iNextPagePos;
|
||||
BooksPos iLastPos;
|
||||
int iOldPageCount;
|
||||
int iPage;
|
||||
};
|
||||
|
||||
BooksBookModel::Task::Task(BooksBookModel* aModel,
|
||||
shared_ptr<Book> aBook, const BooksPos& aPagePos,
|
||||
const BooksPos& aNextPagePos, const BooksPos& aLastPos, int aPageCount) :
|
||||
iBook(aBook),
|
||||
iTextStyle(aModel->textStyle()),
|
||||
iMargins(aModel->margins()),
|
||||
iPaint(aModel->width(), aModel->height()),
|
||||
iData(NULL),
|
||||
iPagePos(aPagePos),
|
||||
iNextPagePos(aNextPagePos),
|
||||
iLastPos(aLastPos),
|
||||
iOldPageCount(aPageCount),
|
||||
iPage(-1)
|
||||
{
|
||||
aModel->connect(this, SIGNAL(done()), SLOT(onResetDone()));
|
||||
aModel->connect(this, SIGNAL(progress(int)), SLOT(onResetProgress(int)),
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
BooksBookModel::Task::~Task()
|
||||
{
|
||||
delete iData;
|
||||
}
|
||||
|
||||
void BooksBookModel::Task::performTask()
|
||||
{
|
||||
if (!isCanceled()) {
|
||||
iData = new BooksBookModel::Data(iPaint.width(), iPaint.height());
|
||||
iData->iBookModel = new BookModel(iBook);
|
||||
shared_ptr<ZLTextModel> model(iData->iBookModel->bookTextModel());
|
||||
ZLTextHyphenator::Instance().load(iBook->language());
|
||||
if (!isCanceled()) {
|
||||
BooksTextView view(iPaint, iTextStyle, iMargins);
|
||||
view.setModel(model);
|
||||
if (model->paragraphsNumber() > 0) {
|
||||
BooksPos mark = view.rewind();
|
||||
iData->iPageMarks.append(mark);
|
||||
Q_EMIT progress(iData->iPageMarks.count());
|
||||
while (!isCanceled() && view.nextPage()) {
|
||||
mark = view.position();
|
||||
iData->iPageMarks.append(mark);
|
||||
Q_EMIT progress(iData->iPageMarks.count());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isCanceled()) {
|
||||
HDEBUG(iData->iPageMarks.count() << "page(s)" << qPrintable(
|
||||
QString("%1x%2").arg(iData->iWidth).arg(iData->iHeight)));
|
||||
iPage = iPagePos.valid() ?
|
||||
iData->pickPage(iPagePos, iNextPagePos, iOldPageCount) :
|
||||
iData->pickPage(iLastPos);
|
||||
} else {
|
||||
HDEBUG("giving up" << qPrintable(QString("%1x%2").arg(iPaint.width()).
|
||||
arg(iPaint.height())) << "paging");
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksBookModel
|
||||
// ==========================================================================
|
||||
|
||||
enum BooksBookModelRole {
|
||||
BooksBookModelPageIndex = Qt::UserRole
|
||||
};
|
||||
|
||||
BooksBookModel::BooksBookModel(QObject* aParent) :
|
||||
QAbstractListModel(aParent),
|
||||
iCurrentPage(-1),
|
||||
iProgress(0),
|
||||
iBook(NULL),
|
||||
iSettings(NULL),
|
||||
iTask(NULL),
|
||||
iData(NULL),
|
||||
iData2(NULL),
|
||||
iTaskQueue(BooksTaskQueue::instance()),
|
||||
iTextStyle(BooksTextStyle::defaults())
|
||||
{
|
||||
HDEBUG("created");
|
||||
#if QT_VERSION < 0x050000
|
||||
setRoleNames(roleNames());
|
||||
#endif
|
||||
}
|
||||
|
||||
BooksBookModel::~BooksBookModel()
|
||||
{
|
||||
if (iTask) iTask->release(this);
|
||||
delete iData;
|
||||
delete iData2;
|
||||
HDEBUG("destroyed");
|
||||
}
|
||||
|
||||
void BooksBookModel::setBook(BooksBook* aBook)
|
||||
{
|
||||
shared_ptr<Book> oldBook;
|
||||
shared_ptr<Book> newBook;
|
||||
if (iBook != aBook) {
|
||||
const QString oldTitle(iTitle);
|
||||
if (iBook) iBook->release();
|
||||
if (aBook) {
|
||||
(iBook = aBook)->retain();
|
||||
iBookRef = newBook;
|
||||
iTitle = iBook->title();
|
||||
HDEBUG(iTitle);
|
||||
} else {
|
||||
iBook = NULL;
|
||||
iBookRef.reset();
|
||||
iTitle = QString();
|
||||
HDEBUG("<none>");
|
||||
}
|
||||
startReset();
|
||||
if (oldTitle != iTitle) {
|
||||
Q_EMIT titleChanged();
|
||||
}
|
||||
Q_EMIT bookModelChanged();
|
||||
Q_EMIT bookChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool BooksBookModel::loading() const
|
||||
{
|
||||
return (iTask != NULL);
|
||||
}
|
||||
|
||||
void BooksBookModel::setSettings(BooksSettings* aSettings)
|
||||
{
|
||||
if (iSettings != aSettings) {
|
||||
shared_ptr<ZLTextStyle> oldTextStyle(iTextStyle);
|
||||
if (iSettings) iSettings->disconnect(this);
|
||||
iSettings = aSettings;
|
||||
if (iSettings) {
|
||||
iTextStyle = iSettings->textStyle();
|
||||
connect(iSettings, SIGNAL(textStyleChanged()), SLOT(onTextStyleChanged()));
|
||||
} else {
|
||||
iTextStyle = BooksTextStyle::defaults();
|
||||
}
|
||||
if (!BooksTextStyle::equalLayout(oldTextStyle, iTextStyle)) {
|
||||
startReset();
|
||||
}
|
||||
Q_EMIT settingsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBookModel::setCurrentPage(int aPage)
|
||||
{
|
||||
if (iCurrentPage != aPage) {
|
||||
iCurrentPage = aPage;
|
||||
if (iData &&
|
||||
iCurrentPage >= 0 &&
|
||||
iCurrentPage < iData->iPageMarks.count()) {
|
||||
iBook->setLastPos(iData->iPageMarks.at(iCurrentPage));
|
||||
HDEBUG(aPage << iBook->lastPos());
|
||||
} else {
|
||||
HDEBUG(aPage);
|
||||
}
|
||||
Q_EMIT currentPageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int BooksBookModel::pageCount() const
|
||||
{
|
||||
return iData ? iData->iPageMarks.count() : 0;
|
||||
}
|
||||
|
||||
BooksPos::List BooksBookModel::pageMarks() const
|
||||
{
|
||||
return iData ? iData->iPageMarks : BooksPos::List();
|
||||
}
|
||||
|
||||
BooksPos BooksBookModel::pageMark(int aPage) const
|
||||
{
|
||||
if (aPage >= 0 && iData) {
|
||||
const int n = iData->iPageMarks.count();
|
||||
if (aPage < n) {
|
||||
return iData->iPageMarks.at(aPage);
|
||||
}
|
||||
}
|
||||
return BooksPos();
|
||||
}
|
||||
|
||||
shared_ptr<BookModel> BooksBookModel::bookModel() const
|
||||
{
|
||||
return iData ? iData->iBookModel : NULL;
|
||||
}
|
||||
|
||||
shared_ptr<ZLTextModel> BooksBookModel::bookTextModel() const
|
||||
{
|
||||
shared_ptr<ZLTextModel> model;
|
||||
if (iData && !iData->iBookModel.isNull()) {
|
||||
model = iData->iBookModel->bookTextModel();
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
shared_ptr<ZLTextModel> BooksBookModel::contentsModel() const
|
||||
{
|
||||
shared_ptr<ZLTextModel> model;
|
||||
if (iData && !iData->iBookModel.isNull()) {
|
||||
model = iData->iBookModel->contentsModel();
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
void BooksBookModel::setLeftMargin(int aMargin)
|
||||
{
|
||||
if (iMargins.iLeft != aMargin) {
|
||||
iMargins.iLeft = aMargin;
|
||||
HDEBUG(aMargin);
|
||||
startReset();
|
||||
Q_EMIT leftMarginChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBookModel::setRightMargin(int aMargin)
|
||||
{
|
||||
if (iMargins.iRight != aMargin) {
|
||||
iMargins.iRight = aMargin;
|
||||
HDEBUG(aMargin);
|
||||
startReset();
|
||||
Q_EMIT rightMarginChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBookModel::setTopMargin(int aMargin)
|
||||
{
|
||||
if (iMargins.iTop != aMargin) {
|
||||
iMargins.iTop = aMargin;
|
||||
HDEBUG(aMargin);
|
||||
startReset();
|
||||
Q_EMIT topMarginChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBookModel::setBottomMargin(int aMargin)
|
||||
{
|
||||
if (iMargins.iBottom != aMargin) {
|
||||
iMargins.iBottom = aMargin;
|
||||
HDEBUG(aMargin);
|
||||
startReset();
|
||||
Q_EMIT bottomMarginChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBookModel::updateModel(int aPrevPageCount)
|
||||
{
|
||||
const int newPageCount = pageCount();
|
||||
if (aPrevPageCount != newPageCount) {
|
||||
if (newPageCount > aPrevPageCount) {
|
||||
beginInsertRows(QModelIndex(), aPrevPageCount, newPageCount-1);
|
||||
endInsertRows();
|
||||
} else {
|
||||
beginRemoveRows(QModelIndex(), newPageCount, aPrevPageCount-1);
|
||||
endRemoveRows();
|
||||
}
|
||||
Q_EMIT pageCountChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBookModel::setSize(QSize aSize)
|
||||
{
|
||||
if (iSize != aSize) {
|
||||
iSize = aSize;
|
||||
const int w = width();
|
||||
const int h = height();
|
||||
HDEBUG(aSize);
|
||||
if (iData && iData->iWidth == w && iData->iHeight == h) {
|
||||
HDEBUG("size didn't change");
|
||||
} else if (iData2 && iData2->iWidth == w && iData2->iHeight == h) {
|
||||
HDEBUG("switching to backup layout");
|
||||
const int oldPageCount(pageCount());
|
||||
BooksPos page1 = pageMark(iCurrentPage);
|
||||
BooksPos page2 = pageMark(iCurrentPage+1);
|
||||
Data* tmp = iData;
|
||||
iData = iData2;
|
||||
iData2 = tmp;
|
||||
if (iData) {
|
||||
// Cancel unnecessary paging task
|
||||
if (iTask) {
|
||||
iTask->release(this);
|
||||
iTask = NULL;
|
||||
}
|
||||
updateModel(oldPageCount);
|
||||
Q_EMIT pageMarksChanged();
|
||||
Q_EMIT jumpToPage(iData->pickPage(page1, page2, oldPageCount));
|
||||
} else {
|
||||
startReset(false);
|
||||
}
|
||||
} else {
|
||||
startReset(false);
|
||||
}
|
||||
Q_EMIT sizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBookModel::onTextStyleChanged()
|
||||
{
|
||||
HDEBUG(iTitle);
|
||||
iTextStyle = iSettings->textStyle();
|
||||
startReset();
|
||||
}
|
||||
|
||||
void BooksBookModel::startReset(bool aFullReset)
|
||||
{
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
const BooksPos thisPage = pageMark(iCurrentPage);
|
||||
const BooksPos nextPage = pageMark(iCurrentPage+1);
|
||||
if (iTask) {
|
||||
iTask->release(this);
|
||||
iTask = NULL;
|
||||
}
|
||||
const int oldPageCount(pageCount());
|
||||
if (oldPageCount > 0) {
|
||||
beginResetModel();
|
||||
}
|
||||
|
||||
delete iData2;
|
||||
if (aFullReset) {
|
||||
delete iData;
|
||||
iData2 = NULL;
|
||||
} else {
|
||||
iData2 = iData;
|
||||
}
|
||||
iData = NULL;
|
||||
|
||||
if (iBook && width() > 0 && height() > 0) {
|
||||
iTask = new Task(this, iBook->bookRef(), thisPage, nextPage,
|
||||
iBook->lastPos(), oldPageCount);
|
||||
iTaskQueue->submit(iTask);
|
||||
}
|
||||
|
||||
if (oldPageCount > 0) {
|
||||
endResetModel();
|
||||
Q_EMIT pageMarksChanged();
|
||||
Q_EMIT pageCountChanged();
|
||||
}
|
||||
|
||||
if (iCurrentPage != 0) {
|
||||
iCurrentPage = 0;
|
||||
Q_EMIT currentPageChanged();
|
||||
}
|
||||
|
||||
if (iProgress != 0) {
|
||||
iProgress = 0;
|
||||
Q_EMIT progressChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBookModel::onResetProgress(int aProgress)
|
||||
{
|
||||
if (iTask && aProgress > iProgress) {
|
||||
iProgress = aProgress;
|
||||
Q_EMIT progressChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksBookModel::onResetDone()
|
||||
{
|
||||
HASSERT(sender() == iTask);
|
||||
HASSERT(iTask->iData);
|
||||
HASSERT(!iData);
|
||||
|
||||
const int oldPageCount(pageCount());
|
||||
shared_ptr<BookModel> oldBookModel(bookModel());
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
int page = iTask->iPage;
|
||||
|
||||
iData = iTask->iData;
|
||||
iTask->iData = NULL;
|
||||
iTask->release(this);
|
||||
iTask = NULL;
|
||||
|
||||
updateModel(oldPageCount);
|
||||
Q_EMIT jumpToPage(page);
|
||||
Q_EMIT pageMarksChanged();
|
||||
if (oldBookModel != bookModel()) {
|
||||
Q_EMIT bookModelChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QHash<int,QByteArray> BooksBookModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles.insert(BooksBookModelPageIndex, "pageIndex");
|
||||
return roles;
|
||||
}
|
||||
|
||||
int BooksBookModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return pageCount();
|
||||
}
|
||||
|
||||
QVariant BooksBookModel::data(const QModelIndex& aIndex, int aRole) const
|
||||
{
|
||||
const int i = aIndex.row();
|
||||
if (i >= 0 && i < pageCount()) {
|
||||
switch (aRole) {
|
||||
case BooksBookModelPageIndex: return i;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
#include "BooksBookModel.moc"
|
168
app/src/BooksBookModel.h
Normal file
168
app/src/BooksBookModel.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_BOOK_MODEL_H
|
||||
#define BOOKS_BOOK_MODEL_H
|
||||
|
||||
#include "BooksBook.h"
|
||||
#include "BooksTask.h"
|
||||
#include "BooksTaskQueue.h"
|
||||
#include "BooksTextView.h"
|
||||
#include "BooksSettings.h"
|
||||
#include "BooksPos.h"
|
||||
#include "BooksPaintContext.h"
|
||||
#include "BooksLoadingProperty.h"
|
||||
|
||||
#include "ZLTextStyle.h"
|
||||
#include "bookmodel/BookModel.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
#include <QAbstractListModel>
|
||||
#include <QtQml>
|
||||
#include <QQuickItem>
|
||||
|
||||
class BooksBookModel: public QAbstractListModel, private BooksLoadingProperty
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
|
||||
Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged)
|
||||
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
|
||||
Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
|
||||
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 rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
|
||||
Q_PROPERTY(int topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
|
||||
Q_PROPERTY(int bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
|
||||
Q_PROPERTY(BooksBook* book READ book WRITE setBook NOTIFY bookChanged)
|
||||
Q_PROPERTY(BooksSettings* settings READ settings WRITE setSettings NOTIFY settingsChanged)
|
||||
|
||||
public:
|
||||
explicit BooksBookModel(QObject* aParent = NULL);
|
||||
~BooksBookModel();
|
||||
|
||||
bool loading() const;
|
||||
int pageCount() const;
|
||||
int progress() const { return iProgress; }
|
||||
QString title() const { return iTitle; }
|
||||
int width() const { return iSize.width(); }
|
||||
int height() const { return iSize.height(); }
|
||||
|
||||
QSize size() const { return iSize; }
|
||||
void setSize(QSize aSize);
|
||||
|
||||
int currentPage() const { return iCurrentPage; }
|
||||
void setCurrentPage(int aPage);
|
||||
|
||||
BooksBook* book() const { return iBook; }
|
||||
void setBook(BooksBook* aBook);
|
||||
|
||||
BooksSettings* settings() const { return iSettings; }
|
||||
void setSettings(BooksSettings* aModel);
|
||||
|
||||
int leftMargin() const { return iMargins.iLeft; }
|
||||
int rightMargin() const { return iMargins.iRight; }
|
||||
int topMargin() const { return iMargins.iTop; }
|
||||
int bottomMargin() const { return iMargins.iBottom; }
|
||||
|
||||
void setLeftMargin(int aMargin);
|
||||
void setRightMargin(int aMargin);
|
||||
void setTopMargin(int aMargin);
|
||||
void setBottomMargin(int aMargin);
|
||||
|
||||
BooksPos::List pageMarks() const;
|
||||
BooksPos pageMark(int aPage) const;
|
||||
BooksMargins margins() const { return iMargins; }
|
||||
shared_ptr<Book> bookRef() const { return iBookRef; }
|
||||
shared_ptr<BookModel> bookModel() const;
|
||||
shared_ptr<ZLTextModel> bookTextModel() const;
|
||||
shared_ptr<ZLTextModel> contentsModel() const;
|
||||
shared_ptr<ZLTextStyle> textStyle() const { return iTextStyle; }
|
||||
|
||||
// QAbstractListModel
|
||||
virtual QHash<int,QByteArray> roleNames() const;
|
||||
virtual int rowCount(const QModelIndex& aParent) const;
|
||||
virtual QVariant data(const QModelIndex& aIndex, int aRole) const;
|
||||
|
||||
private:
|
||||
void updateSize();
|
||||
void updateModel(int aPrevPageCount);
|
||||
void startReset(bool aFullReset = true);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onResetProgress(int aProgress);
|
||||
void onResetDone();
|
||||
void onTextStyleChanged();
|
||||
|
||||
Q_SIGNALS:
|
||||
void sizeChanged();
|
||||
void bookChanged();
|
||||
void bookModelChanged();
|
||||
void titleChanged();
|
||||
void loadingChanged();
|
||||
void pageCountChanged();
|
||||
void pageMarksChanged();
|
||||
void progressChanged();
|
||||
void currentPageChanged();
|
||||
void settingsChanged();
|
||||
void leftMarginChanged();
|
||||
void rightMarginChanged();
|
||||
void topMarginChanged();
|
||||
void bottomMarginChanged();
|
||||
void jumpToPage(int index);
|
||||
|
||||
private:
|
||||
class Data;
|
||||
class Task;
|
||||
|
||||
int iCurrentPage;
|
||||
int iProgress;
|
||||
QSize iSize;
|
||||
QString iTitle;
|
||||
BooksMargins iMargins;
|
||||
BooksBook* iBook;
|
||||
shared_ptr<Book> iBookRef;
|
||||
BooksSettings* iSettings;
|
||||
Task* iTask;
|
||||
Data* iData;
|
||||
Data* iData2;
|
||||
shared_ptr<BooksTaskQueue> iTaskQueue;
|
||||
shared_ptr<ZLTextStyle> iTextStyle;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(BooksBookModel)
|
||||
|
||||
#endif // BOOKS_BOOK_MODEL_H
|
156
app/src/BooksConfig.cpp
Normal file
156
app/src/BooksConfig.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksConfig.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
// ==========================================================================
|
||||
// BooksConfig::Private
|
||||
// ==========================================================================
|
||||
|
||||
class BooksConfig::Private
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
// ==========================================================================
|
||||
// BooksConfig
|
||||
// ==========================================================================
|
||||
|
||||
BooksConfig::BooksConfig() : iPrivate(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
BooksConfig::~BooksConfig()
|
||||
{
|
||||
delete iPrivate;
|
||||
}
|
||||
|
||||
void
|
||||
BooksConfig::listOptionNames(
|
||||
const std::string& aGroup,
|
||||
std::vector<std::string>& names)
|
||||
{
|
||||
HDEBUG(aGroup.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
BooksConfig::listOptionGroups(
|
||||
std::vector<std::string>& aGroups)
|
||||
{
|
||||
HDEBUG("sorry...");
|
||||
}
|
||||
|
||||
void
|
||||
BooksConfig::removeGroup(
|
||||
const std::string& aName)
|
||||
{
|
||||
HDEBUG(aName.c_str());
|
||||
}
|
||||
|
||||
const std::string&
|
||||
BooksConfig::getDefaultValue(
|
||||
const std::string& aGroup,
|
||||
const std::string& aName,
|
||||
const std::string& aDefault) const
|
||||
{
|
||||
HDEBUG(aGroup.c_str() << aName.c_str() << "(" << aDefault.c_str() << ")");
|
||||
return aDefault;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
BooksConfig::getValue(
|
||||
const std::string& aGroup,
|
||||
const std::string& aName,
|
||||
const std::string& aDefault) const
|
||||
{
|
||||
HDEBUG(aGroup.c_str() << aName.c_str() << "(" << aDefault.c_str() << ")");
|
||||
return aDefault;
|
||||
}
|
||||
|
||||
void
|
||||
BooksConfig::setValue(
|
||||
const std::string& aGroup,
|
||||
const std::string& aName,
|
||||
const std::string& aValue,
|
||||
const std::string& aCategory)
|
||||
{
|
||||
HDEBUG(aGroup.c_str() << aName.c_str() << aValue.c_str() << aCategory.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
BooksConfig::unsetValue(
|
||||
const std::string& aGroup,
|
||||
const std::string& aName)
|
||||
{
|
||||
HDEBUG(aGroup.c_str() << aName.c_str());
|
||||
}
|
||||
|
||||
bool BooksConfig::isAutoSavingSupported() const
|
||||
{
|
||||
HDEBUG("NO");
|
||||
return false;
|
||||
}
|
||||
|
||||
void BooksConfig::startAutoSave(int aSeconds)
|
||||
{
|
||||
HDEBUG(aSeconds);
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksConfigManager
|
||||
// ==========================================================================
|
||||
|
||||
BooksConfigManager::BooksConfigManager()
|
||||
{
|
||||
HASSERT(!ourInstance);
|
||||
HASSERT(!ourIsInitialised);
|
||||
ourInstance = this;
|
||||
}
|
||||
|
||||
BooksConfigManager::~BooksConfigManager()
|
||||
{
|
||||
HASSERT(ourInstance == this);
|
||||
if (ourInstance == this) {
|
||||
ourInstance = NULL;
|
||||
ourIsInitialised = false;
|
||||
}
|
||||
}
|
||||
|
||||
ZLConfig* BooksConfigManager::createConfig() const
|
||||
{
|
||||
ZLConfig* config = new BooksConfig();
|
||||
ourIsInitialised = true;
|
||||
return config;
|
||||
}
|
74
app/src/BooksConfig.h
Normal file
74
app/src/BooksConfig.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_CONFIG_H
|
||||
#define BOOKS_CONFIG_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
#include <ZLConfig.h>
|
||||
|
||||
class BooksConfigManager : public ZLConfigManager {
|
||||
public:
|
||||
BooksConfigManager();
|
||||
~BooksConfigManager();
|
||||
ZLConfig* createConfig() const;
|
||||
};
|
||||
|
||||
class BooksConfig : public ZLConfig
|
||||
{
|
||||
public:
|
||||
BooksConfig();
|
||||
~BooksConfig();
|
||||
|
||||
// ZLConfig
|
||||
void listOptionNames(const std::string& aGroup, std::vector<std::string>& names);
|
||||
void listOptionGroups(std::vector<std::string>& aGroups);
|
||||
void removeGroup(const std::string& aName);
|
||||
|
||||
const std::string& getDefaultValue(const std::string& aGroup, const std::string& aName, const std::string& aDefault) const;
|
||||
const std::string& getValue(const std::string& aGroup, const std::string& aName, const std::string& aDefault) const;
|
||||
void setValue(const std::string& aGroup, const std::string& aName, const std::string& aValue, const std::string& aCategory);
|
||||
void unsetValue(const std::string& aGroup, const std::string& aName);
|
||||
|
||||
bool isAutoSavingSupported() const;
|
||||
void startAutoSave(int aSeconds);
|
||||
|
||||
private:
|
||||
void updateRenderType();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* iPrivate;
|
||||
};
|
||||
|
||||
#endif // BOOKS_CONFIG_H
|
138
app/src/BooksCoverModel.cpp
Normal file
138
app/src/BooksCoverModel.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksCoverModel.h"
|
||||
#include "BooksShelf.h"
|
||||
#include "BooksBook.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
BooksCoverModel::BooksCoverModel(QObject* aParent) :
|
||||
QSortFilterProxyModel(aParent)
|
||||
{
|
||||
connect(this, SIGNAL(sourceModelChanged()), SIGNAL(sourceChanged()));
|
||||
}
|
||||
|
||||
bool BooksCoverModel::filterAcceptsRow(int aRow, const QModelIndex& aParent) const
|
||||
{
|
||||
BooksShelf* shelf = qobject_cast<BooksShelf*>(sourceModel());
|
||||
if (shelf) {
|
||||
BooksBook* book = qobject_cast<BooksBook*>(shelf->get(aRow));
|
||||
if (book) {
|
||||
return book->hasCoverImage();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int BooksCoverModel::count() const
|
||||
{
|
||||
return rowCount(QModelIndex());
|
||||
}
|
||||
|
||||
void BooksCoverModel::setSource(QObject* aSrc)
|
||||
{
|
||||
QAbstractItemModel* oldM = sourceModel();
|
||||
if (aSrc != oldM) {
|
||||
const int oldCount = count();
|
||||
if (oldM) {
|
||||
BooksShelf* oldShelf = qobject_cast<BooksShelf*>(oldM);
|
||||
if (oldShelf) {
|
||||
const int n = oldShelf->count();
|
||||
for (int i=0; i<n; i++) {
|
||||
onBookRemoved(oldShelf->bookAt(i));
|
||||
}
|
||||
}
|
||||
oldM->disconnect(this);
|
||||
}
|
||||
if (aSrc) {
|
||||
QAbstractItemModel* newM = qobject_cast<QAbstractItemModel*>(aSrc);
|
||||
if (newM) {
|
||||
setSourceModel(newM);
|
||||
BooksShelf* newShelf = qobject_cast<BooksShelf*>(newM);
|
||||
if (newShelf) {
|
||||
const int n = newShelf->count();
|
||||
for (int i=0; i<n; i++) {
|
||||
onBookAdded(newShelf->bookAt(i));
|
||||
}
|
||||
connect(newShelf,
|
||||
SIGNAL(bookAdded(BooksBook*)),
|
||||
SLOT(onBookAdded(BooksBook*)));
|
||||
connect(newShelf,
|
||||
SIGNAL(bookRemoved(BooksBook*)),
|
||||
SLOT(onBookRemoved(BooksBook*)));
|
||||
}
|
||||
connect(newM,
|
||||
SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||
SIGNAL(countChanged()));
|
||||
connect(newM,
|
||||
SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||||
SIGNAL(countChanged()));
|
||||
connect(newM,
|
||||
SIGNAL(modelReset()),
|
||||
SIGNAL(countChanged()));
|
||||
} else {
|
||||
HDEBUG("unexpected source" << aSrc);
|
||||
setSourceModel(NULL);
|
||||
}
|
||||
} else {
|
||||
setSourceModel(NULL);
|
||||
}
|
||||
if (oldCount != count()) {
|
||||
Q_EMIT countChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverModel::onCoverImageChanged()
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
Q_EMIT countChanged();
|
||||
}
|
||||
|
||||
void BooksCoverModel::onBookAdded(BooksBook* aBook)
|
||||
{
|
||||
if (aBook) {
|
||||
connect(aBook,
|
||||
SIGNAL(coverImageChanged()),
|
||||
SLOT(onCoverImageChanged()));
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverModel::onBookRemoved(BooksBook* aBook)
|
||||
{
|
||||
if (aBook) {
|
||||
aBook->disconnect(this);
|
||||
}
|
||||
}
|
67
app/src/BooksCoverModel.h
Normal file
67
app/src/BooksCoverModel.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_COVER_MODEL_H
|
||||
#define BOOKS_COVER_MODEL_H
|
||||
|
||||
#include "BooksBook.h"
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QtQml>
|
||||
|
||||
class BooksCoverModel: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||
Q_PROPERTY(QObject* source READ sourceModel WRITE setSource NOTIFY sourceChanged)
|
||||
|
||||
public:
|
||||
explicit BooksCoverModel(QObject* aParent = NULL);
|
||||
|
||||
int count() const;
|
||||
void setSource(QObject* aSource);
|
||||
bool filterAcceptsRow(int aRow, const QModelIndex& aParent) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void countChanged();
|
||||
void sourceChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onCoverImageChanged();
|
||||
void onBookAdded(BooksBook* aBook);
|
||||
void onBookRemoved(BooksBook* aBook);
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(BooksCoverModel)
|
||||
|
||||
#endif // BOOKS_COVER_MODEL_H
|
463
app/src/BooksCoverWidget.cpp
Normal file
463
app/src/BooksCoverWidget.cpp
Normal file
|
@ -0,0 +1,463 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksCoverWidget.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include "ZLibrary.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
// ==========================================================================
|
||||
// BooksCoverWidget::ScaleTask
|
||||
// ==========================================================================
|
||||
|
||||
class BooksCoverWidget::ScaleTask : public BooksTask
|
||||
{
|
||||
public:
|
||||
ScaleTask(QImage aImage, int aWidth, int aHeight, bool aStretch);
|
||||
static QImage scale(QImage aImage, int aWidth, int aHeight, bool aStretch);
|
||||
void performTask();
|
||||
|
||||
public:
|
||||
QImage iImage;
|
||||
QImage iScaledImage;
|
||||
int iWidth;
|
||||
int iHeight;
|
||||
bool iStretch;
|
||||
};
|
||||
|
||||
BooksCoverWidget::ScaleTask::ScaleTask(QImage aImage, int aWidth, int aHeight,
|
||||
bool aStretch) :
|
||||
iImage(aImage),
|
||||
iWidth(aWidth),
|
||||
iHeight(aHeight),
|
||||
iStretch(aStretch)
|
||||
{
|
||||
}
|
||||
|
||||
QImage BooksCoverWidget::ScaleTask::scale(QImage aImage,
|
||||
int aWidth, int aHeight, bool aStretch)
|
||||
{
|
||||
if (aStretch){
|
||||
return aImage.scaled(aWidth, aHeight, Qt::KeepAspectRatioByExpanding,
|
||||
Qt::SmoothTransformation);
|
||||
} else {
|
||||
return (aWidth*aImage.height() > aImage.width()*aHeight) ?
|
||||
aImage.scaledToHeight(aHeight, Qt::SmoothTransformation) :
|
||||
aImage.scaledToWidth(aWidth, Qt::SmoothTransformation);
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::ScaleTask::performTask()
|
||||
{
|
||||
if (!iImage.isNull() && !isCanceled()) {
|
||||
iScaledImage = scale(iImage, iWidth, iHeight, iStretch);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksCoverWidget::DefaultImage
|
||||
// ==========================================================================
|
||||
|
||||
// Image shared by all items in the bookshelf view
|
||||
class BooksCoverWidget::DefaultImage
|
||||
{
|
||||
public:
|
||||
static QImage scaled(int aWidth, int aHeight);
|
||||
static QImage* retain();
|
||||
static void release(QImage* aImage);
|
||||
|
||||
private:
|
||||
static const char* iImageName;
|
||||
static QImage* iImage;
|
||||
static QImage* iScaledImage;
|
||||
static int iRefCount;
|
||||
static bool iMissing;
|
||||
};
|
||||
|
||||
const char* BooksCoverWidget::DefaultImage::iImageName = "default-cover.jpg";
|
||||
QImage* BooksCoverWidget::DefaultImage::iImage = NULL;
|
||||
QImage* BooksCoverWidget::DefaultImage::iScaledImage = NULL;
|
||||
int BooksCoverWidget::DefaultImage::iRefCount = 0;
|
||||
bool BooksCoverWidget::DefaultImage::iMissing = false;
|
||||
|
||||
QImage* BooksCoverWidget::DefaultImage::retain()
|
||||
{
|
||||
if (!iImage && !iMissing) {
|
||||
QString path(QString::fromStdString(
|
||||
ZLibrary::DefaultFilesPathPrefix() + iImageName));
|
||||
iImage = new QImage(path);
|
||||
if (iImage->isNull() || !iImage->width() || !iImage->height()) {
|
||||
HWARN("Failed to load" << qPrintable(path));
|
||||
delete iImage;
|
||||
iImage = NULL;
|
||||
iMissing = true;
|
||||
} else {
|
||||
HDEBUG("loaded" << qPrintable(path));
|
||||
}
|
||||
}
|
||||
if (iImage) {
|
||||
iRefCount++;
|
||||
}
|
||||
return iImage;
|
||||
}
|
||||
|
||||
QImage BooksCoverWidget::DefaultImage::scaled(int aWidth, int aHeight)
|
||||
{
|
||||
QImage scaled;
|
||||
HASSERT(iImage);
|
||||
if (iImage) {
|
||||
const int iw = iImage->width();
|
||||
const int ih = iImage->height();
|
||||
if (aWidth*ih > iw*aHeight) {
|
||||
// Scaling to height
|
||||
if (iScaledImage && iScaledImage->height() != aHeight) {
|
||||
delete iScaledImage;
|
||||
iScaledImage = NULL;
|
||||
}
|
||||
if (iScaledImage) {
|
||||
scaled = *iScaledImage;
|
||||
} else {
|
||||
HDEBUG("scaling to height" << aHeight);
|
||||
scaled = iImage->scaledToHeight(aHeight,
|
||||
Qt::SmoothTransformation);
|
||||
iScaledImage = new QImage(scaled);
|
||||
}
|
||||
} else {
|
||||
// Scaling to width
|
||||
if (iScaledImage && iScaledImage->width() != aWidth) {
|
||||
delete iScaledImage;
|
||||
iScaledImage = NULL;
|
||||
}
|
||||
if (iScaledImage) {
|
||||
scaled = *iScaledImage;
|
||||
} else {
|
||||
HDEBUG("scaling to width" << aHeight);
|
||||
scaled = iImage->scaledToWidth(aWidth,
|
||||
Qt::SmoothTransformation);
|
||||
iScaledImage = new QImage(scaled);
|
||||
}
|
||||
}
|
||||
}
|
||||
return scaled;
|
||||
}
|
||||
|
||||
void BooksCoverWidget::DefaultImage::release(QImage* aImage)
|
||||
{
|
||||
if (aImage) {
|
||||
HASSERT(aImage == iImage);
|
||||
if (!(--iRefCount)) {
|
||||
HDEBUG("deleting cached image");
|
||||
if (iImage) {
|
||||
delete iImage;
|
||||
iImage = NULL;
|
||||
}
|
||||
if (iScaledImage) {
|
||||
delete iScaledImage;
|
||||
iScaledImage = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksViewWidget
|
||||
// ==========================================================================
|
||||
|
||||
BooksCoverWidget::BooksCoverWidget(QQuickItem* aParent) :
|
||||
QQuickPaintedItem(aParent),
|
||||
iTaskQueue(BooksTaskQueue::instance()),
|
||||
iScaleTask(NULL),
|
||||
iBook(NULL),
|
||||
iDefaultImage(NULL),
|
||||
iBorderWidth(0),
|
||||
iBorderRadius(0),
|
||||
iBorderColor(Qt::transparent),
|
||||
iStretch(false),
|
||||
iSynchronous(false)
|
||||
{
|
||||
setFlag(ItemHasContents, true);
|
||||
setFillColor(Qt::transparent);
|
||||
connect(this, SIGNAL(widthChanged()), SLOT(onSizeChanged()));
|
||||
connect(this, SIGNAL(heightChanged()), SLOT(onSizeChanged()));
|
||||
}
|
||||
|
||||
BooksCoverWidget::~BooksCoverWidget()
|
||||
{
|
||||
HDEBUG(iTitle);
|
||||
DefaultImage::release(iDefaultImage);
|
||||
if (iScaleTask) iScaleTask->release(this);
|
||||
if (iBook) iBook->release();
|
||||
}
|
||||
|
||||
void BooksCoverWidget::setBook(BooksBook* aBook)
|
||||
{
|
||||
if (iBook != aBook) {
|
||||
const bool wasEmpty(empty());
|
||||
const bool wasLoading = loading();
|
||||
if (iBook) {
|
||||
iBook->disconnect(this);
|
||||
iBook->release();
|
||||
}
|
||||
if (aBook) {
|
||||
(iBook = aBook)->retain();
|
||||
iBook->requestCoverImage();
|
||||
iBookRef = iBook->bookRef();
|
||||
iCoverImage = iBook->coverImage();
|
||||
iTitle = iBook->title();
|
||||
connect(iBook,
|
||||
SIGNAL(loadingCoverChanged()),
|
||||
SIGNAL(loadingChanged()));
|
||||
connect(iBook,
|
||||
SIGNAL(coverImageChanged()),
|
||||
SLOT(onCoverImageChanged()));
|
||||
HDEBUG(iTitle);
|
||||
} else {
|
||||
iBook = NULL;
|
||||
iBookRef.reset();
|
||||
iCoverImage = QImage();
|
||||
iTitle.clear();
|
||||
HDEBUG("<none>");
|
||||
}
|
||||
scaleImage(wasEmpty);
|
||||
Q_EMIT bookChanged();
|
||||
if (wasLoading != loading()) {
|
||||
Q_EMIT loadingChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::onCoverImageChanged()
|
||||
{
|
||||
HDEBUG(iTitle);
|
||||
const bool wasEmpty(empty());
|
||||
iCoverImage = iBook->coverImage();
|
||||
scaleImage(wasEmpty);
|
||||
}
|
||||
|
||||
void BooksCoverWidget::setStretch(bool aValue)
|
||||
{
|
||||
if (iStretch != aValue) {
|
||||
iStretch = aValue;
|
||||
HDEBUG(aValue);
|
||||
scaleImage();
|
||||
Q_EMIT stretchChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::setSynchronous(bool aValue)
|
||||
{
|
||||
if (iSynchronous != aValue) {
|
||||
iSynchronous = aValue;
|
||||
HDEBUG(aValue);
|
||||
Q_EMIT synchronousChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::setBorderWidth(qreal aWidth)
|
||||
{
|
||||
if (iBorderWidth != aWidth && aWidth >= 0) {
|
||||
iBorderWidth = aWidth;
|
||||
HDEBUG(iBorderWidth);
|
||||
update();
|
||||
Q_EMIT borderWidthChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::setBorderRadius(qreal aRadius)
|
||||
{
|
||||
if (iBorderRadius != aRadius && aRadius >= 0) {
|
||||
iBorderRadius = aRadius;
|
||||
HDEBUG(iBorderRadius);
|
||||
update();
|
||||
Q_EMIT borderRadiusChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::setBorderColor(QColor aColor)
|
||||
{
|
||||
if (iBorderColor != aColor) {
|
||||
iBorderColor = aColor;
|
||||
HDEBUG(iBorderColor);
|
||||
update();
|
||||
Q_EMIT borderColorChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::setDefaultCover(QUrl aUrl)
|
||||
{
|
||||
if (iDefaultCover != aUrl) {
|
||||
iDefaultCover = aUrl;
|
||||
HDEBUG(iDefaultCover);
|
||||
scaleImage();
|
||||
Q_EMIT defaultCoverChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::onSizeChanged()
|
||||
{
|
||||
scaleImage();
|
||||
}
|
||||
|
||||
bool BooksCoverWidget::empty() const
|
||||
{
|
||||
return !iBook || !iBook->hasCoverImage() ||
|
||||
iScaleTask || iScaledImage.isNull();
|
||||
}
|
||||
|
||||
bool BooksCoverWidget::loading() const
|
||||
{
|
||||
return iBook && iBook->loadingCover();
|
||||
}
|
||||
|
||||
void BooksCoverWidget::scaleImage(bool aWasEmpty)
|
||||
{
|
||||
const int w = width();
|
||||
const int h = height();
|
||||
|
||||
iScaledImage = QImage();
|
||||
if (iScaleTask) {
|
||||
iScaleTask->release(this);
|
||||
iScaleTask = NULL;
|
||||
}
|
||||
|
||||
if (w > 0 && h > 0) {
|
||||
if ((!iBook || !iBook->hasCoverImage()) && iDefaultCover.isValid()) {
|
||||
QString path(iDefaultCover.toLocalFile());
|
||||
if (!iCoverImage.load(path)) {
|
||||
HWARN("Failed to load" << qPrintable(path));
|
||||
}
|
||||
}
|
||||
if (iCoverImage.isNull()) {
|
||||
if (!iDefaultImage) iDefaultImage = DefaultImage::retain();
|
||||
if (iDefaultImage) iCoverImage = *iDefaultImage;
|
||||
}
|
||||
|
||||
if (!iCoverImage.isNull()) {
|
||||
if (iSynchronous) {
|
||||
iScaledImage = ScaleTask::scale(iCoverImage, w, h, iStretch);
|
||||
update();
|
||||
} else {
|
||||
iScaledImage = QImage();
|
||||
iScaleTask = new ScaleTask(iCoverImage, w, h, iStretch);
|
||||
connect(iScaleTask, SIGNAL(done()), SLOT(onScaleTaskDone()));
|
||||
iTaskQueue->submit(iScaleTask);
|
||||
}
|
||||
} else {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
if (aWasEmpty != empty()) {
|
||||
Q_EMIT emptyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::onScaleTaskDone()
|
||||
{
|
||||
const bool wasEmpty(empty());
|
||||
HASSERT(iScaleTask == sender());
|
||||
iScaledImage = iScaleTask->iScaledImage;
|
||||
iScaleTask->release(this);
|
||||
iScaleTask = NULL;
|
||||
update();
|
||||
if (wasEmpty != empty()) {
|
||||
Q_EMIT emptyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksCoverWidget::paint(QPainter* aPainter)
|
||||
{
|
||||
const qreal w = width();
|
||||
const qreal h = height();
|
||||
if (w > 0 && h > 0) {
|
||||
qreal sw, sh;
|
||||
if (!iScaledImage.isNull()) {
|
||||
sw = iScaledImage.width();
|
||||
sh = iScaledImage.height();
|
||||
} else {
|
||||
sw = w;
|
||||
sh = h;
|
||||
}
|
||||
|
||||
const int x = (w - sw)/2;
|
||||
const int y = h - sh;
|
||||
|
||||
QPainterPath path;
|
||||
qreal w1, h1, x1, y1;
|
||||
|
||||
if (iBorderRadius > 0) {
|
||||
// The border rectangle is no less that 3*radius
|
||||
// and no more than the size of the item.
|
||||
const qreal d = 2*iBorderRadius;
|
||||
w1 = qMin(w, qMax(sw, 2*d)) - iBorderWidth;
|
||||
h1 = qMin(h, qMax(sh, 3*d)) - iBorderWidth;
|
||||
x1 = (w - w1)/2;
|
||||
y1 = h - h1 - iBorderWidth/2;
|
||||
|
||||
const qreal x2 = x1 + w1 - d;
|
||||
const qreal y2 = y1 + h1 - d;
|
||||
path.arcMoveTo(x1, y1, d, d, 180);
|
||||
path.arcTo(x1, y1, d, d, 180, -90);
|
||||
path.arcTo(x2, y1, d, d, 90, -90);
|
||||
path.arcTo(x2, y2, d, d, 0, -90);
|
||||
path.arcTo(x1, y2, d, d, 270, -90);
|
||||
path.closeSubpath();
|
||||
aPainter->setClipPath(path);
|
||||
} else {
|
||||
w1 = sw - iBorderWidth;
|
||||
h1 = sh - iBorderWidth;
|
||||
x1 = (w - w1)/2;
|
||||
y1 = h - h1 - iBorderWidth/2;
|
||||
}
|
||||
|
||||
if (!iScaledImage.isNull()) {
|
||||
aPainter->drawImage(x, y, iScaledImage);
|
||||
}
|
||||
|
||||
if (iBorderColor.alpha() && iBorderWidth > 0) {
|
||||
aPainter->setRenderHint(QPainter::Antialiasing);
|
||||
aPainter->setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
aPainter->setBrush(Qt::NoBrush);
|
||||
aPainter->setPen(QPen(iBorderColor, iBorderWidth));
|
||||
if (iBorderRadius > 0) {
|
||||
aPainter->setClipping(false);
|
||||
aPainter->drawPath(path);
|
||||
} else {
|
||||
aPainter->drawRect(x1, y1, w1, h1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
129
app/src/BooksCoverWidget.h
Normal file
129
app/src/BooksCoverWidget.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_COVER_WIDGET_H
|
||||
#define BOOKS_COVER_WIDGET_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
#include "BooksTask.h"
|
||||
#include "BooksTaskQueue.h"
|
||||
#include "BooksBook.h"
|
||||
|
||||
#include "ZLImage.h"
|
||||
#include "image/ZLQtImageManager.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QQuickPaintedItem>
|
||||
|
||||
class BooksCoverWidget: public QQuickPaintedItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool empty READ empty NOTIFY emptyChanged)
|
||||
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
|
||||
Q_PROPERTY(bool stretch READ stretch WRITE setStretch NOTIFY stretchChanged)
|
||||
Q_PROPERTY(bool synchronous READ synchronous WRITE setSynchronous NOTIFY synchronousChanged)
|
||||
Q_PROPERTY(qreal borderWidth READ borderWidth WRITE setBorderWidth NOTIFY borderWidthChanged)
|
||||
Q_PROPERTY(qreal borderRadius READ borderRadius WRITE setBorderRadius NOTIFY borderRadiusChanged)
|
||||
Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor NOTIFY borderColorChanged)
|
||||
Q_PROPERTY(QUrl defaultCover READ defaultCover WRITE setDefaultCover NOTIFY defaultCoverChanged)
|
||||
Q_PROPERTY(BooksBook* book READ book WRITE setBook NOTIFY bookChanged)
|
||||
|
||||
public:
|
||||
BooksCoverWidget(QQuickItem* aParent = NULL);
|
||||
~BooksCoverWidget();
|
||||
|
||||
bool empty() const;
|
||||
bool loading() const;
|
||||
|
||||
qreal borderWidth() const { return iBorderRadius; }
|
||||
void setBorderWidth(qreal aWidth);
|
||||
|
||||
qreal borderRadius() const { return iBorderRadius; }
|
||||
void setBorderRadius(qreal aRadius);
|
||||
|
||||
QColor borderColor() const { return iBorderColor; }
|
||||
void setBorderColor(QColor aColor);
|
||||
|
||||
QUrl defaultCover() const { return iDefaultCover; }
|
||||
void setDefaultCover(QUrl aUrl);
|
||||
|
||||
BooksBook* book() const { return iBook; }
|
||||
void setBook(BooksBook* aBook);
|
||||
|
||||
bool stretch() const { return iStretch; }
|
||||
void setStretch(bool aValue);
|
||||
|
||||
bool synchronous() const { return iSynchronous; }
|
||||
void setSynchronous(bool aValue);
|
||||
|
||||
Q_SIGNALS:
|
||||
void bookChanged();
|
||||
void emptyChanged();
|
||||
void loadingChanged();
|
||||
void stretchChanged();
|
||||
void synchronousChanged();
|
||||
void borderWidthChanged();
|
||||
void borderRadiusChanged();
|
||||
void borderColorChanged();
|
||||
void defaultCoverChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onCoverImageChanged();
|
||||
void onSizeChanged();
|
||||
void onScaleTaskDone();
|
||||
|
||||
private:
|
||||
void paint(QPainter *painter);
|
||||
void scaleImage(bool aWasEmpty);
|
||||
void scaleImage() { scaleImage(empty()); }
|
||||
|
||||
private:
|
||||
class ScaleTask;
|
||||
class DefaultImage;
|
||||
shared_ptr<BooksTaskQueue> iTaskQueue;
|
||||
ScaleTask* iScaleTask;
|
||||
QImage iScaledImage;
|
||||
QImage iCoverImage;
|
||||
shared_ptr<Book> iBookRef;
|
||||
BooksBook* iBook;
|
||||
QImage* iDefaultImage;
|
||||
qreal iBorderWidth;
|
||||
qreal iBorderRadius;
|
||||
QColor iBorderColor;
|
||||
QUrl iDefaultCover;
|
||||
QString iTitle;
|
||||
bool iStretch;
|
||||
bool iSynchronous;
|
||||
};
|
||||
|
||||
#endif // BOOKS_COVER_WIDGET_H
|
65
app/src/BooksDefs.h
Normal file
65
app/src/BooksDefs.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_DEFS_H
|
||||
#define BOOKS_DEFS_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
#define BOOKS_APP_NAME "harbour-books"
|
||||
#define BOOKS_DATA_ROOT "usr/share/" BOOKS_APP_NAME
|
||||
#define BOOKS_QML_DIR BOOKS_DATA_ROOT "/qml"
|
||||
#define BOOKS_ICONS_DIR BOOKS_DATA_ROOT "/icons"
|
||||
#define BOOKS_DATA_DIR BOOKS_DATA_ROOT "/data"
|
||||
#define BOOKS_QML_FILE BOOKS_QML_DIR "/BooksMain.qml"
|
||||
|
||||
#define BOOKS_ROOT_SHELF_DIR "Books"
|
||||
|
||||
#define BOOKS_QML_PLUGIN "harbour.books"
|
||||
#define BOOKS_QML_PLUGIN_V1 1
|
||||
#define BOOKS_QML_PLUGIN_V2 0
|
||||
#define BOOKS_QML_REGISTER(klass,name) \
|
||||
qmlRegisterType<klass>(BOOKS_QML_PLUGIN, BOOKS_QML_PLUGIN_V1, \
|
||||
BOOKS_QML_PLUGIN_V2, name)
|
||||
|
||||
#define BOOKS_STATE_FILE_SUFFIX ".state"
|
||||
|
||||
#if defined(__i386__)
|
||||
# define BOOKS_PPI (330) // Tablet 1536x2048
|
||||
#elif defined(__arm__)
|
||||
# define BOOKS_PPI (245) // Jolla1 540x960
|
||||
#else
|
||||
# error Unexpected architechture
|
||||
#endif
|
||||
|
||||
#endif // BOOKS_DEFS_H
|
142
app/src/BooksDialogManager.cpp
Normal file
142
app/src/BooksDialogManager.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksDialogManager.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include "ZLDialog.h"
|
||||
#include "ZLOptionsDialog.h"
|
||||
#include "ZLProgressDialog.h"
|
||||
#include "image/ZLQtImageManager.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QClipboard>
|
||||
|
||||
void BooksDialogManager::createApplicationWindow(ZLApplication* aApp) const
|
||||
{
|
||||
HDEBUG("THIS IS NOT SUPPOSED TO HAPPEN!");
|
||||
}
|
||||
|
||||
shared_ptr<ZLDialog>
|
||||
BooksDialogManager::createDialog(
|
||||
const ZLResourceKey& aKey) const
|
||||
{
|
||||
HDEBUG(aKey.Name.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shared_ptr<ZLOptionsDialog>
|
||||
BooksDialogManager::createOptionsDialog(
|
||||
const ZLResourceKey& aKey,
|
||||
shared_ptr<ZLRunnable> aApplyAction,
|
||||
bool aApplyButton) const
|
||||
{
|
||||
HDEBUG(aKey.Name.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shared_ptr<ZLOpenFileDialog>
|
||||
BooksDialogManager::createOpenFileDialog(
|
||||
const ZLResourceKey& aKey,
|
||||
const std::string& aDirPath,
|
||||
const std::string& aFilePath,
|
||||
const ZLOpenFileDialog::Filter& aFilter) const
|
||||
{
|
||||
HDEBUG(aKey.Name.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
BooksDialogManager::informationBox(
|
||||
const std::string& title,
|
||||
const std::string& message) const
|
||||
{
|
||||
HDEBUG(QString::fromStdString(title) << message.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
BooksDialogManager::errorBox(
|
||||
const ZLResourceKey& key,
|
||||
const std::string& message) const
|
||||
{
|
||||
HDEBUG(QString::fromStdString(key.Name) << message.c_str());
|
||||
}
|
||||
|
||||
int
|
||||
BooksDialogManager::questionBox(
|
||||
const ZLResourceKey& key,
|
||||
const std::string& message,
|
||||
const ZLResourceKey& button0,
|
||||
const ZLResourceKey& button1,
|
||||
const ZLResourceKey& button2) const
|
||||
{
|
||||
HDEBUG(QString::fromStdString(key.Name) << message.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
shared_ptr<ZLProgressDialog>
|
||||
BooksDialogManager::createProgressDialog(
|
||||
const ZLResourceKey& aKey) const
|
||||
{
|
||||
HDEBUG(aKey.Name.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
BooksDialogManager::isClipboardSupported(
|
||||
ClipboardType aType) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BooksDialogManager::setClipboardText(
|
||||
const std::string& text,
|
||||
ClipboardType type) const
|
||||
{
|
||||
if (!text.empty()) {
|
||||
QGuiApplication::clipboard()->setText(QString::fromStdString(text),
|
||||
(type == CLIPBOARD_MAIN) ? QClipboard::Clipboard : QClipboard::Selection);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BooksDialogManager::setClipboardImage(
|
||||
const ZLImageData &imageData,
|
||||
ClipboardType type) const
|
||||
{
|
||||
QGuiApplication::clipboard()->setImage(
|
||||
*static_cast<const ZLQtImageData&>(imageData).image(),
|
||||
(type == CLIPBOARD_MAIN) ? QClipboard::Clipboard : QClipboard::Selection);
|
||||
}
|
66
app/src/BooksDialogManager.h
Normal file
66
app/src/BooksDialogManager.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_DIALOG_MANAGER_H
|
||||
#define BOOKS_DIALOG_MANAGER_H
|
||||
|
||||
#include <ZLDialogManager.h>
|
||||
|
||||
class BooksDialogManager: public ZLDialogManager {
|
||||
|
||||
public:
|
||||
static void createInstance() { ourInstance = new BooksDialogManager(); }
|
||||
|
||||
private:
|
||||
BooksDialogManager() {}
|
||||
|
||||
public:
|
||||
static const ZLResource& resource(const ZLResourceKey& aKey)
|
||||
{ return ZLDialogManager::resource()[aKey]; }
|
||||
|
||||
void createApplicationWindow(ZLApplication *application) const;
|
||||
|
||||
shared_ptr<ZLDialog> createDialog(const ZLResourceKey &key) const;
|
||||
shared_ptr<ZLOptionsDialog> createOptionsDialog(const ZLResourceKey &key, shared_ptr<ZLRunnable> applyAction, bool showApplyButton) const;
|
||||
shared_ptr<ZLOpenFileDialog> createOpenFileDialog(const ZLResourceKey &key, const std::string &directoryPath, const std::string &filePath, const ZLOpenFileDialog::Filter &filter) const;
|
||||
void informationBox(const std::string &title, const std::string &message) const;
|
||||
void errorBox(const ZLResourceKey &key, const std::string &message) const;
|
||||
int questionBox(const ZLResourceKey &key, const std::string &message, const ZLResourceKey &button0, const ZLResourceKey &button1, const ZLResourceKey &button2) const;
|
||||
shared_ptr<ZLProgressDialog> createProgressDialog(const ZLResourceKey &key) const;
|
||||
|
||||
bool isClipboardSupported(ClipboardType type) const;
|
||||
void setClipboardText(const std::string &text, ClipboardType type) const;
|
||||
void setClipboardImage(const ZLImageData &imageData, ClipboardType type) const;
|
||||
};
|
||||
|
||||
#endif /* BOOKS_DIALOG_MANAGER_H */
|
403
app/src/BooksImportModel.cpp
Normal file
403
app/src/BooksImportModel.cpp
Normal file
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksImportModel.h"
|
||||
#include "BooksStorage.h"
|
||||
#include "BooksTask.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QCryptographicHash>
|
||||
|
||||
enum BooksImportRole {
|
||||
BooksImportRoleTitle = Qt::UserRole,
|
||||
BooksImportRoleBook,
|
||||
BooksImportRolePath,
|
||||
BooksImportRoleFileName,
|
||||
BooksImportRoleSelected
|
||||
};
|
||||
|
||||
// ==========================================================================
|
||||
// BooksImportModel::Data
|
||||
// ==========================================================================
|
||||
|
||||
class BooksImportModel::Data {
|
||||
public:
|
||||
Data(BooksBook* iBook);
|
||||
~Data();
|
||||
|
||||
QString title() { return iBook->title(); }
|
||||
QString path() { return iBook->path(); }
|
||||
QString fileName() { return iBook->fileName(); }
|
||||
|
||||
public:
|
||||
BooksBook* iBook;
|
||||
bool iSelected;
|
||||
};
|
||||
|
||||
BooksImportModel::Data::Data(BooksBook* aBook) :
|
||||
iBook(aBook),
|
||||
iSelected(false)
|
||||
{
|
||||
iBook->retain();
|
||||
}
|
||||
|
||||
BooksImportModel::Data::~Data()
|
||||
{
|
||||
iBook->release();
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksImportModel::Task
|
||||
// ==========================================================================
|
||||
|
||||
class BooksImportModel::Task : public BooksTask
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Task(QString aDest) : iDestDir(aDest), iBufSize(0x1000), iBuf(NULL) {}
|
||||
~Task();
|
||||
|
||||
void performTask();
|
||||
void scanDir(QDir aDir);
|
||||
bool isDuplicate(QString aPath, QFileInfoList aFileList);
|
||||
QByteArray calculateFileHash(QString aPath);
|
||||
QByteArray getFileHash(QString aPath);
|
||||
|
||||
Q_SIGNALS:
|
||||
void bookFound(BooksBook* aBook) const;
|
||||
|
||||
public:
|
||||
QList<BooksBook*> iBooks;
|
||||
QHash<QString,QByteArray> iFileHash;
|
||||
QHash<QByteArray,QString> iHashFile;
|
||||
QFileInfoList iDestFiles;
|
||||
QFileInfoList iSrcFiles;
|
||||
QString iDestDir;
|
||||
qint64 iBufSize;
|
||||
char* iBuf;
|
||||
};
|
||||
|
||||
BooksImportModel::Task::~Task()
|
||||
{
|
||||
const int n = iBooks.count();
|
||||
for (int i=0; i<n; i++) iBooks.at(i)->release();
|
||||
delete [] iBuf;
|
||||
}
|
||||
|
||||
QByteArray BooksImportModel::Task::calculateFileHash(QString aPath)
|
||||
{
|
||||
QByteArray result;
|
||||
QFile file(aPath);
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
qint64 len;
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
hash.reset();
|
||||
if (!iBuf) iBuf = new char[iBufSize];
|
||||
while (!isCanceled() && (len = file.read(iBuf, iBufSize)) > 0) {
|
||||
hash.addData(iBuf, len);
|
||||
}
|
||||
if (len == 0) {
|
||||
if (!isCanceled()) {
|
||||
result = hash.result();
|
||||
HDEBUG(qPrintable(aPath) << QString(result.toHex()));
|
||||
}
|
||||
} else {
|
||||
HWARN("error reading" << qPrintable(aPath));
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray BooksImportModel::Task::getFileHash(QString aPath)
|
||||
{
|
||||
if (iFileHash.contains(aPath)) {
|
||||
return iFileHash.value(aPath);
|
||||
} else {
|
||||
QByteArray hash = calculateFileHash(aPath);
|
||||
iFileHash.insert(aPath, hash);
|
||||
iHashFile.insert(hash, aPath);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
bool BooksImportModel::Task::isDuplicate(QString aPath, QFileInfoList aList)
|
||||
{
|
||||
const int n = aList.count();
|
||||
if (n > 0) {
|
||||
QFileInfo file(aPath);
|
||||
QByteArray fileHash;
|
||||
for (int i=0; i<n && !isCanceled(); i++) {
|
||||
QFileInfo other = aList.at(i);
|
||||
if (other.size() == file.size()) {
|
||||
QByteArray otherHash(getFileHash(other.filePath()));
|
||||
if (!otherHash.isEmpty() && !isCanceled()) {
|
||||
if (fileHash.isEmpty()) fileHash = getFileHash(aPath);
|
||||
if (fileHash == otherHash) {
|
||||
HDEBUG(qPrintable(aPath) << "and" <<
|
||||
qPrintable(other.filePath()) <<
|
||||
"are identical");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BooksImportModel::Task::performTask()
|
||||
{
|
||||
if (!isCanceled()) {
|
||||
if (!iDestDir.isEmpty()) {
|
||||
iDestFiles = QDir(iDestDir).entryInfoList(QDir::Files);
|
||||
}
|
||||
scanDir(QDir(QDir::homePath() + "/Downloads"));
|
||||
}
|
||||
}
|
||||
|
||||
void BooksImportModel::Task::scanDir(QDir aDir)
|
||||
{
|
||||
// Files first
|
||||
if (!isCanceled()) {
|
||||
HDEBUG("checking" << aDir.canonicalPath());
|
||||
QFileInfoList fileList = aDir.entryInfoList(QDir::Files |
|
||||
QDir::Readable, QDir::Time);
|
||||
const int n = fileList.count();
|
||||
for (int i=0; i<n && !isCanceled(); i++) {
|
||||
QFileInfo fileInfo(fileList.at(i));
|
||||
QString filePath(fileInfo.canonicalFilePath());
|
||||
std::string path(filePath.toStdString());
|
||||
ZLFile file(path);
|
||||
shared_ptr<Book> book = Book::loadFromFile(file);
|
||||
if (!book.isNull()) {
|
||||
if (!isDuplicate(filePath, iDestFiles) &&
|
||||
!isDuplicate(filePath, iSrcFiles)) {
|
||||
BooksBook* newBook = new BooksBook(BooksStorage(), book);
|
||||
newBook->moveToThread(thread());
|
||||
iBooks.append(newBook);
|
||||
iSrcFiles.append(fileInfo);
|
||||
HDEBUG("found" << path.c_str() << newBook->title());
|
||||
Q_EMIT bookFound(newBook);
|
||||
}
|
||||
} else {
|
||||
HDEBUG("not a book:" << path.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then directories
|
||||
if (!isCanceled()) {
|
||||
QFileInfoList dirList = aDir.entryInfoList(QDir::Dirs |
|
||||
QDir::NoDotAndDotDot | QDir::Readable, QDir::Time);
|
||||
const int n = dirList.count();
|
||||
for (int i=0; i<n && !isCanceled(); i++) {
|
||||
QString dirPath(dirList.at(i).canonicalFilePath());
|
||||
HDEBUG(dirPath);
|
||||
if (!dirPath.isEmpty()) {
|
||||
scanDir(QDir(dirPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksImportModel
|
||||
// ==========================================================================
|
||||
|
||||
BooksImportModel::BooksImportModel(QObject* aParent) :
|
||||
QAbstractListModel(aParent),
|
||||
iSelectedCount(0),
|
||||
iAutoRefresh(false),
|
||||
iTaskQueue(BooksTaskQueue::instance()),
|
||||
iTask(NULL)
|
||||
{
|
||||
iSelectedRole.append(BooksImportRoleSelected);
|
||||
HDEBUG("created");
|
||||
#if QT_VERSION < 0x050000
|
||||
setRoleNames(roleNames());
|
||||
#endif
|
||||
}
|
||||
|
||||
BooksImportModel::~BooksImportModel()
|
||||
{
|
||||
HDEBUG("destroyed");
|
||||
qDeleteAll(iList);
|
||||
if (iTask) iTask->release(this);
|
||||
}
|
||||
|
||||
void BooksImportModel::setDestination(QString aDestination)
|
||||
{
|
||||
if (iDestination != aDestination) {
|
||||
iDestination = aDestination;
|
||||
HDEBUG(aDestination);
|
||||
Q_EMIT destinationChanged();
|
||||
if (iAutoRefresh) {
|
||||
if (iTask) {
|
||||
iTask->release(this);
|
||||
iTask = NULL;
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksImportModel::refresh()
|
||||
{
|
||||
iAutoRefresh = true;
|
||||
if (!iTask) {
|
||||
HDEBUG("refreshing the model");
|
||||
|
||||
if (!iList.isEmpty()) {
|
||||
beginResetModel();
|
||||
qDeleteAll(iList);
|
||||
iList.clear();
|
||||
endInsertRows();
|
||||
Q_EMIT countChanged();
|
||||
}
|
||||
|
||||
iTask = new Task(iDestination);
|
||||
connect(iTask, SIGNAL(bookFound(BooksBook*)),
|
||||
SLOT(onBookFound(BooksBook*)), Qt::QueuedConnection);
|
||||
connect(iTask, SIGNAL(done()), SLOT(onTaskDone()));
|
||||
iTaskQueue->submit(iTask);
|
||||
Q_EMIT busyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksImportModel::setSelected(int aIndex, bool aSelected)
|
||||
{
|
||||
if (validIndex(aIndex)) {
|
||||
Data* data = iList.at(aIndex);
|
||||
if (data->iSelected != aSelected) {
|
||||
HDEBUG(data->path() << aSelected);
|
||||
if (data->iSelected) iSelectedCount--;
|
||||
if (aSelected) iSelectedCount++;
|
||||
data->iSelected = aSelected;
|
||||
|
||||
QModelIndex index(createIndex(aIndex, 0));
|
||||
Q_EMIT dataChanged(index, index, iSelectedRole);
|
||||
Q_EMIT selectedCountChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QObject* BooksImportModel::selectedBook(int aIndex)
|
||||
{
|
||||
const int n = iList.count();
|
||||
for (int i=0, k=0; i<n; i++) {
|
||||
Data* data = iList.at(i);
|
||||
if (data->iSelected) {
|
||||
if (k == aIndex) {
|
||||
return data->iBook;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void BooksImportModel::onBookFound(BooksBook* aBook)
|
||||
{
|
||||
if (iTask) {
|
||||
// When we find the first book, we add two items. The second item
|
||||
// is the "virtual" that will stay at the end of the list and will
|
||||
// be removed by onTaskDone() after scanning is finished. The idea
|
||||
// is to show the busy indicator at the end of the list (that's how
|
||||
// QML represents the dummy item) while we keep on scanning.
|
||||
const int n1 = iList.count();
|
||||
beginInsertRows(QModelIndex(), n1, n1 ? n1 : 1);
|
||||
iList.append(new Data(aBook));
|
||||
endInsertRows();
|
||||
Q_EMIT countChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksImportModel::onTaskDone()
|
||||
{
|
||||
HASSERT(iTask);
|
||||
HASSERT(iTask == sender());
|
||||
iTask->release(this);
|
||||
iTask = NULL;
|
||||
if (iList.count() > 0) {
|
||||
// Remove the "virtual" item at the end of the list
|
||||
beginRemoveRows(QModelIndex(),iList.count(), iList.count());
|
||||
endRemoveRows();
|
||||
}
|
||||
Q_EMIT busyChanged();
|
||||
}
|
||||
|
||||
QHash<int,QByteArray> BooksImportModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles.insert(BooksImportRoleTitle, "title");
|
||||
roles.insert(BooksImportRoleBook, "book");
|
||||
roles.insert(BooksImportRolePath, "path");
|
||||
roles.insert(BooksImportRoleFileName, "fileName");
|
||||
roles.insert(BooksImportRoleSelected, "selected");
|
||||
return roles;
|
||||
}
|
||||
|
||||
int BooksImportModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return iTask ? (iList.count() + 1) : iList.count();
|
||||
}
|
||||
|
||||
QVariant BooksImportModel::data(const QModelIndex& aIndex, int aRole) const
|
||||
{
|
||||
const int i = aIndex.row();
|
||||
if (validIndex(i)) {
|
||||
Data* data = iList.at(i);
|
||||
switch (aRole) {
|
||||
case BooksImportRoleTitle: return data->title();
|
||||
case BooksImportRoleBook: return QVariant::fromValue(data->iBook);
|
||||
case BooksImportRolePath: return data->path();
|
||||
case BooksImportRoleFileName: return data->fileName();
|
||||
case BooksImportRoleSelected: return data->iSelected;
|
||||
}
|
||||
} else if (i == iList.count()) {
|
||||
switch (aRole) {
|
||||
case BooksImportRoleTitle:
|
||||
case BooksImportRolePath:
|
||||
case BooksImportRoleFileName: return QString();
|
||||
case BooksImportRoleBook: return QVariant::fromValue((QObject*)NULL);
|
||||
case BooksImportRoleSelected: return false;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
#include "BooksImportModel.moc"
|
103
app/src/BooksImportModel.h
Normal file
103
app/src/BooksImportModel.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_IMPORT_MODEL_H
|
||||
#define BOOKS_IMPORT_MODEL_H
|
||||
|
||||
#include "BooksBook.h"
|
||||
#include "BooksTaskQueue.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
#include <QAbstractListModel>
|
||||
#include <QtQml>
|
||||
|
||||
class BooksImportModel: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
||||
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||
Q_PROPERTY(int selectedCount READ selectedCount NOTIFY selectedCountChanged)
|
||||
Q_PROPERTY(QString destination READ destination WRITE setDestination NOTIFY destinationChanged)
|
||||
|
||||
public:
|
||||
explicit BooksImportModel(QObject* aParent = NULL);
|
||||
~BooksImportModel();
|
||||
|
||||
bool busy() const { return iTask != NULL; }
|
||||
int count() const { return iList.count(); }
|
||||
int selectedCount() const { return iSelectedCount; }
|
||||
QString destination() const { return iDestination; }
|
||||
void setDestination(QString aDestination);
|
||||
|
||||
Q_INVOKABLE void refresh();
|
||||
Q_INVOKABLE void setSelected(int aIndex, bool aSelected);
|
||||
Q_INVOKABLE QObject* selectedBook(int aIndex);
|
||||
|
||||
// QAbstractListModel
|
||||
virtual QHash<int,QByteArray> roleNames() const;
|
||||
virtual int rowCount(const QModelIndex& aParent) const;
|
||||
virtual QVariant data(const QModelIndex& aIndex, int aRole) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void countChanged();
|
||||
void busyChanged();
|
||||
void selectedCountChanged();
|
||||
void destinationChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onBookFound(BooksBook* aBook);
|
||||
void onTaskDone();
|
||||
|
||||
private:
|
||||
bool validIndex(int aIndex) const;
|
||||
|
||||
private:
|
||||
class Task;
|
||||
class Data;
|
||||
QString iDestination;
|
||||
QList<Data*> iList;
|
||||
QVector<int> iSelectedRole;
|
||||
int iSelectedCount;
|
||||
bool iAutoRefresh;
|
||||
shared_ptr<BooksTaskQueue> iTaskQueue;
|
||||
Task* iTask;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(BooksImportModel)
|
||||
|
||||
inline bool BooksImportModel::validIndex(int aIndex) const
|
||||
{ return aIndex >= 0 && aIndex < iList.count(); }
|
||||
|
||||
#endif // BOOKS_IMPORT_MODEL_H
|
57
app/src/BooksItem.h
Normal file
57
app/src/BooksItem.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_ITEM_H
|
||||
#define BOOKS_ITEM_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
|
||||
class BooksItem
|
||||
{
|
||||
public:
|
||||
virtual ~BooksItem() {}
|
||||
|
||||
virtual BooksItem* retain() = 0;
|
||||
virtual void release() = 0;
|
||||
|
||||
virtual QObject* object() = 0;
|
||||
virtual BooksShelf* shelf() = 0;
|
||||
virtual BooksBook* book() = 0;
|
||||
virtual QString name() const = 0;
|
||||
virtual QString fileName() const = 0;
|
||||
};
|
||||
|
||||
#endif // BOOKS_ITEM_H
|
200
app/src/BooksListWatcher.cpp
Normal file
200
app/src/BooksListWatcher.cpp
Normal file
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksListWatcher.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#define LISTVIEW_CONTENT_X "contentX"
|
||||
#define LISTVIEW_CONTENT_Y "contentY"
|
||||
#define LISTVIEW_INDEX_AT "indexAt"
|
||||
|
||||
BooksListWatcher::BooksListWatcher(QObject* aParent) :
|
||||
QObject(aParent),
|
||||
iCurrentIndex(0),
|
||||
iContentX(0),
|
||||
iContentY(0),
|
||||
iListView(NULL),
|
||||
iResizeTimer(new QTimer(this))
|
||||
{
|
||||
iResizeTimer->setSingleShot(true);
|
||||
iResizeTimer->setInterval(0);
|
||||
connect(iResizeTimer, SIGNAL(timeout()), SLOT(onResizeTimeout()));
|
||||
}
|
||||
|
||||
void BooksListWatcher::setListView(QQuickItem* aView)
|
||||
{
|
||||
if (iListView != aView) {
|
||||
const QSize oldSize(iSize);
|
||||
if (iListView) iListView->disconnect(this);
|
||||
iListView = aView;
|
||||
if (iListView) {
|
||||
connect(iListView,
|
||||
SIGNAL(widthChanged()),
|
||||
SLOT(onWidthChanged()));
|
||||
connect(iListView,
|
||||
SIGNAL(heightChanged()),
|
||||
SLOT(onHeightChanged()));
|
||||
connect(iListView,
|
||||
SIGNAL(contentXChanged()),
|
||||
SLOT(onContentXChanged()));
|
||||
connect(iListView,
|
||||
SIGNAL(contentYChanged()),
|
||||
SLOT(onContentYChanged()));
|
||||
connect(iListView,
|
||||
SIGNAL(contentWidthChanged()),
|
||||
SLOT(onContentSizeChanged()));
|
||||
connect(iListView,
|
||||
SIGNAL(contentHeightChanged()),
|
||||
SLOT(onContentSizeChanged()));
|
||||
iContentX = contentX();
|
||||
iContentY = contentY();
|
||||
updateCurrentIndex();
|
||||
} else {
|
||||
iContentX = iContentY = 0;
|
||||
iSize = QSize(0,0);
|
||||
}
|
||||
Q_EMIT listViewChanged();
|
||||
if (oldSize != iSize) {
|
||||
Q_EMIT sizeChanged();
|
||||
}
|
||||
if (oldSize.width() != iSize.width()) {
|
||||
Q_EMIT widthChanged();
|
||||
}
|
||||
if (oldSize.height() != iSize.height()) {
|
||||
Q_EMIT heightChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qreal BooksListWatcher::getRealProperty(const char *name, qreal defaultValue)
|
||||
{
|
||||
QVariant value = iListView->property(name);
|
||||
bool ok = false;
|
||||
if (value.isValid()) {
|
||||
ok = false;
|
||||
qreal r = value.toReal(&ok);
|
||||
if (ok) return r;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
qreal BooksListWatcher::contentX()
|
||||
{
|
||||
return getRealProperty(LISTVIEW_CONTENT_X);
|
||||
}
|
||||
|
||||
qreal BooksListWatcher::contentY()
|
||||
{
|
||||
return getRealProperty(LISTVIEW_CONTENT_Y);
|
||||
}
|
||||
|
||||
void BooksListWatcher::updateCurrentIndex()
|
||||
{
|
||||
int index = -1;
|
||||
if (QMetaObject::invokeMethod(iListView, LISTVIEW_INDEX_AT,
|
||||
Q_RETURN_ARG(int,index), Q_ARG(qreal,iContentX+width()/2),
|
||||
Q_ARG(qreal,iContentY+height()/2))) {
|
||||
if (iCurrentIndex != index) {
|
||||
HDEBUG(index);
|
||||
iCurrentIndex = index;
|
||||
Q_EMIT currentIndexChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksListWatcher::updateSize()
|
||||
{
|
||||
const QSize size(iListView->width(), iListView->height());
|
||||
HDEBUG(size);
|
||||
if (iSize != size) {
|
||||
const QSize oldSize(iSize);
|
||||
iSize = size;
|
||||
Q_EMIT sizeChanged();
|
||||
if (oldSize.width() != iSize.width()) {
|
||||
Q_EMIT widthChanged();
|
||||
}
|
||||
if (oldSize.height() != iSize.height()) {
|
||||
Q_EMIT heightChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksListWatcher::onWidthChanged()
|
||||
{
|
||||
HASSERT(sender() == iListView);
|
||||
HDEBUG(iListView->width());
|
||||
// Width change will probably be followed by height change
|
||||
iResizeTimer->start();
|
||||
}
|
||||
|
||||
void BooksListWatcher::onHeightChanged()
|
||||
{
|
||||
HASSERT(sender() == iListView);
|
||||
HDEBUG(iListView->height());
|
||||
if (iResizeTimer->isActive()) {
|
||||
// Height is usually changed after width
|
||||
iResizeTimer->stop();
|
||||
updateSize();
|
||||
} else {
|
||||
iResizeTimer->start();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksListWatcher::onResizeTimeout()
|
||||
{
|
||||
// This can only happen if only width or height has changed. Normally,
|
||||
// width change is followed by height change and view is reset from the
|
||||
// setHeight() method
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void BooksListWatcher::onContentXChanged()
|
||||
{
|
||||
HASSERT(sender() == iListView);
|
||||
iContentX = contentX();
|
||||
updateCurrentIndex();
|
||||
}
|
||||
|
||||
void BooksListWatcher::onContentYChanged()
|
||||
{
|
||||
HASSERT(sender() == iListView);
|
||||
iContentY = contentY();
|
||||
updateCurrentIndex();
|
||||
}
|
||||
|
||||
void BooksListWatcher::onContentSizeChanged()
|
||||
{
|
||||
HASSERT(sender() == iListView);
|
||||
updateCurrentIndex();
|
||||
}
|
95
app/src/BooksListWatcher.h
Normal file
95
app/src/BooksListWatcher.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_LIST_WATCHER_H
|
||||
#define BOOKS_LIST_WATCHER_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QtQml>
|
||||
|
||||
class BooksListWatcher: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int currentIndex READ currentIndex NOTIFY currentIndexChanged)
|
||||
Q_PROPERTY(QQuickItem* listView READ listView WRITE setListView NOTIFY listViewChanged)
|
||||
Q_PROPERTY(qreal width READ width NOTIFY widthChanged)
|
||||
Q_PROPERTY(qreal height READ height NOTIFY heightChanged)
|
||||
Q_PROPERTY(QSize size READ size NOTIFY sizeChanged)
|
||||
|
||||
public:
|
||||
explicit BooksListWatcher(QObject* aParent = NULL);
|
||||
|
||||
int currentIndex() const { return iCurrentIndex; }
|
||||
QSize size() const { return iSize; }
|
||||
qreal width() const { return iSize.width(); }
|
||||
qreal height() const { return iSize.height(); }
|
||||
|
||||
QQuickItem* listView() const { return iListView; }
|
||||
void setListView(QQuickItem* aView);
|
||||
|
||||
private:
|
||||
qreal contentX();
|
||||
qreal contentY();
|
||||
qreal getRealProperty(const char *name, qreal defaultValue = 0.0);
|
||||
void updateCurrentIndex();
|
||||
void updateSize();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onResizeTimeout();
|
||||
void onWidthChanged();
|
||||
void onHeightChanged();
|
||||
void onContentXChanged();
|
||||
void onContentYChanged();
|
||||
void onContentSizeChanged();
|
||||
|
||||
Q_SIGNALS:
|
||||
void listViewChanged();
|
||||
void sizeChanged();
|
||||
void widthChanged();
|
||||
void heightChanged();
|
||||
void currentIndexChanged();
|
||||
|
||||
private:
|
||||
QSize iSize;
|
||||
int iCurrentIndex;
|
||||
qreal iContentX;
|
||||
qreal iContentY;
|
||||
QQuickItem* iListView;
|
||||
QTimer* iResizeTimer;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(BooksListWatcher)
|
||||
|
||||
#endif // BOOKS_LIST_WATCHER_H
|
53
app/src/BooksLoadingProperty.cpp
Normal file
53
app/src/BooksLoadingProperty.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksLoadingProperty.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
void BooksLoadingProperty::suspendLoadingStateChanges()
|
||||
{
|
||||
if (!(iChangesBlocked++)) {
|
||||
iSavedState = loading();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksLoadingProperty::resumeLoadingStateChanges()
|
||||
{
|
||||
HASSERT(iChangesBlocked > 0);
|
||||
if (!(--iChangesBlocked)) {
|
||||
if (iSavedState != loading()) {
|
||||
Q_EMIT loadingChanged();
|
||||
}
|
||||
}
|
||||
}
|
69
app/src/BooksLoadingProperty.h
Normal file
69
app/src/BooksLoadingProperty.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_LOADING_PROPERTY_H
|
||||
#define BOOKS_LOADING_PROPERTY_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
|
||||
class BooksLoadingSignalBlocker;
|
||||
|
||||
class BooksLoadingProperty
|
||||
{
|
||||
friend class BooksLoadingSignalBlocker;
|
||||
|
||||
public:
|
||||
BooksLoadingProperty() : iChangesBlocked(0), iSavedState(false) {}
|
||||
|
||||
virtual bool loading() const = 0;
|
||||
virtual void loadingChanged() = 0;
|
||||
|
||||
private:
|
||||
void suspendLoadingStateChanges();
|
||||
void resumeLoadingStateChanges();
|
||||
|
||||
int iChangesBlocked;
|
||||
bool iSavedState;
|
||||
};
|
||||
|
||||
class BooksLoadingSignalBlocker {
|
||||
public:
|
||||
BooksLoadingSignalBlocker(BooksLoadingProperty* aProperty) : iProperty(aProperty)
|
||||
{ iProperty->suspendLoadingStateChanges(); }
|
||||
~BooksLoadingSignalBlocker()
|
||||
{ iProperty->resumeLoadingStateChanges(); }
|
||||
private:
|
||||
BooksLoadingProperty* iProperty;
|
||||
};
|
||||
|
||||
#endif // BOOKS_LOADING_PROPERTY_H
|
474
app/src/BooksPageWidget.cpp
Normal file
474
app/src/BooksPageWidget.cpp
Normal file
|
@ -0,0 +1,474 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksPageWidget.h"
|
||||
#include "BooksTextStyle.h"
|
||||
#include "BooksDefs.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
// ==========================================================================
|
||||
// BooksPageWidget::Data
|
||||
// ==========================================================================
|
||||
|
||||
class BooksPageWidget::Data {
|
||||
public:
|
||||
Data(shared_ptr<ZLTextModel> aModel, int aWidth, int aHeight) :
|
||||
iModel(aModel), iPaintContext(aWidth, aHeight) {}
|
||||
|
||||
bool paint(QPainter* aPainter);
|
||||
|
||||
public:
|
||||
shared_ptr<ZLView> iView;
|
||||
shared_ptr<ZLTextModel> iModel;
|
||||
BooksPaintContext iPaintContext;
|
||||
};
|
||||
|
||||
bool BooksPageWidget::Data::paint(QPainter* aPainter)
|
||||
{
|
||||
if (!iView.isNull()) {
|
||||
iPaintContext.beginPaint(aPainter);
|
||||
iView->paint();
|
||||
iPaintContext.endPaint();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksPageWidget::ResetTask
|
||||
// ==========================================================================
|
||||
|
||||
class BooksPageWidget::ResetTask : public BooksTask
|
||||
{
|
||||
public:
|
||||
ResetTask(shared_ptr<ZLTextModel> aModel,
|
||||
shared_ptr<ZLTextStyle> aTextStyle, int aWidth, int aHeight,
|
||||
const BooksMargins& aMargins, const BooksPos& aPosition);
|
||||
~ResetTask();
|
||||
|
||||
void performTask();
|
||||
|
||||
public:
|
||||
BooksPageWidget::Data* iData;
|
||||
shared_ptr<ZLTextStyle> iTextStyle;
|
||||
BooksMargins iMargins;
|
||||
BooksPos iPosition;
|
||||
};
|
||||
|
||||
BooksPageWidget::ResetTask::ResetTask(shared_ptr<ZLTextModel> aModel,
|
||||
shared_ptr<ZLTextStyle> aTextStyle, int aWidth, int aHeight,
|
||||
const BooksMargins& aMargins, const BooksPos& aPosition) :
|
||||
iData(new BooksPageWidget::Data(aModel, aWidth, aHeight)),
|
||||
iTextStyle(aTextStyle),
|
||||
iMargins(aMargins),
|
||||
iPosition(aPosition)
|
||||
{
|
||||
}
|
||||
|
||||
BooksPageWidget::ResetTask::~ResetTask()
|
||||
{
|
||||
delete iData;
|
||||
}
|
||||
|
||||
void BooksPageWidget::ResetTask::performTask()
|
||||
{
|
||||
if (!isCanceled()) {
|
||||
BooksTextView* view = new BooksTextView(iData->iPaintContext,
|
||||
iTextStyle, iMargins);
|
||||
if (!isCanceled()) {
|
||||
view->setModel(iData->iModel);
|
||||
if (!isCanceled()) {
|
||||
view->gotoPosition(iPosition);
|
||||
if (!isCanceled()) {
|
||||
iData->iView = view;
|
||||
} else {
|
||||
delete view;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksPageWidget::RenderTask
|
||||
// ==========================================================================
|
||||
|
||||
class BooksPageWidget::RenderTask : public BooksTask {
|
||||
public:
|
||||
RenderTask(shared_ptr<BooksPageWidget::Data> aData, int aWidth, int aHeight) :
|
||||
iData(aData), iWidth(aWidth), iHeight(aHeight), iImage(NULL) {}
|
||||
|
||||
void performTask();
|
||||
|
||||
public:
|
||||
shared_ptr<BooksPageWidget::Data> iData;
|
||||
int iWidth;
|
||||
int iHeight;
|
||||
shared_ptr<QImage> iImage;
|
||||
};
|
||||
|
||||
void BooksPageWidget::RenderTask::performTask()
|
||||
{
|
||||
if (!isCanceled() && !iData.isNull() && !iData->iView.isNull() &&
|
||||
iWidth > 0 && iHeight > 0) {
|
||||
iImage = new QImage(iWidth, iHeight, QImage::Format_RGB32);
|
||||
if (!isCanceled()) {
|
||||
QPainter painter(&*iImage);
|
||||
iData->paint(&painter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksPageWidget
|
||||
// ==========================================================================
|
||||
|
||||
BooksPageWidget::BooksPageWidget(QQuickItem* aParent) :
|
||||
QQuickPaintedItem(aParent),
|
||||
iTaskQueue(BooksTaskQueue::instance()),
|
||||
iTextStyle(BooksTextStyle::defaults()),
|
||||
iResizeTimer(new QTimer(this)),
|
||||
iModel(NULL),
|
||||
iSettings(NULL),
|
||||
iResetTask(NULL),
|
||||
iRenderTask(NULL),
|
||||
iPaintRequest(false),
|
||||
iEmpty(false),
|
||||
iPage(-1)
|
||||
{
|
||||
setFlag(ItemHasContents, true);
|
||||
setFillColor(Qt::white);
|
||||
iResizeTimer->setSingleShot(true);
|
||||
iResizeTimer->setInterval(0);
|
||||
connect(iResizeTimer, SIGNAL(timeout()), SLOT(onResizeTimeout()));
|
||||
connect(this, SIGNAL(widthChanged()), SLOT(onWidthChanged()));
|
||||
connect(this, SIGNAL(heightChanged()), SLOT(onHeightChanged()));
|
||||
}
|
||||
|
||||
BooksPageWidget::~BooksPageWidget()
|
||||
{
|
||||
HDEBUG("page" << iPage);
|
||||
if (iResetTask) iResetTask->release(this);
|
||||
if (iRenderTask) iRenderTask->release(this);
|
||||
}
|
||||
|
||||
void BooksPageWidget::setModel(BooksBookModel* aModel)
|
||||
{
|
||||
if (iModel != aModel) {
|
||||
if (iModel) {
|
||||
iModel->disconnect(this);
|
||||
iModel = NULL;
|
||||
}
|
||||
iModel = aModel;
|
||||
if (iModel) {
|
||||
#if HARBOUR_DEBUG
|
||||
if (iPage >= 0) {
|
||||
HDEBUG(iModel->title() << iPage);
|
||||
} else {
|
||||
HDEBUG(iModel->title());
|
||||
}
|
||||
#endif // HARBOUR_DEBUG
|
||||
iPageMark = iModel->pageMark(iPage);
|
||||
connect(iModel, SIGNAL(bookModelChanged()),
|
||||
SLOT(onBookModelChanged()));
|
||||
connect(iModel, SIGNAL(destroyed()),
|
||||
SLOT(onBookModelDestroyed()));
|
||||
connect(iModel, SIGNAL(pageMarksChanged()),
|
||||
SLOT(onBookModelPageMarksChanged()));
|
||||
connect(iModel, SIGNAL(loadingChanged()),
|
||||
SLOT(onBookModelLoadingChanged()));
|
||||
} else {
|
||||
iPageMark.invalidate();
|
||||
}
|
||||
resetView();
|
||||
Q_EMIT modelChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::setSettings(BooksSettings* aSettings)
|
||||
{
|
||||
if (iSettings != aSettings) {
|
||||
shared_ptr<ZLTextStyle> oldTextStyle(iTextStyle);
|
||||
if (iSettings) iSettings->disconnect(this);
|
||||
iSettings = aSettings;
|
||||
if (iSettings) {
|
||||
iTextStyle = iSettings->textStyle();
|
||||
connect(iSettings, SIGNAL(textStyleChanged()), SLOT(onTextStyleChanged()));
|
||||
} else {
|
||||
iTextStyle = BooksTextStyle::defaults();
|
||||
}
|
||||
if (!BooksTextStyle::equalLayout(oldTextStyle, iTextStyle)) {
|
||||
resetView();
|
||||
}
|
||||
Q_EMIT settingsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::onTextStyleChanged()
|
||||
{
|
||||
HDEBUG(iPage);
|
||||
iTextStyle = iSettings->textStyle();
|
||||
resetView();
|
||||
}
|
||||
|
||||
void BooksPageWidget::onBookModelChanged()
|
||||
{
|
||||
HDEBUG(iModel->title());
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
iPageMark = iModel->pageMark(iPage);
|
||||
resetView();
|
||||
}
|
||||
|
||||
void BooksPageWidget::onBookModelDestroyed()
|
||||
{
|
||||
HDEBUG("model destroyed");
|
||||
HASSERT(iModel == sender());
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
iModel = NULL;
|
||||
Q_EMIT modelChanged();
|
||||
resetView();
|
||||
}
|
||||
|
||||
void BooksPageWidget::onBookModelPageMarksChanged()
|
||||
{
|
||||
const BooksPos pos = iModel->pageMark(iPage);
|
||||
if (iPageMark != pos) {
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
iPageMark = pos;
|
||||
HDEBUG("page" << iPage);
|
||||
resetView();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::onBookModelLoadingChanged()
|
||||
{
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
if (!iModel->loading()) {
|
||||
HDEBUG("page" << iPage);
|
||||
const BooksPos pos = iModel->pageMark(iPage);
|
||||
if (iPageMark != pos) {
|
||||
iPageMark = pos;
|
||||
resetView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::setPage(int aPage)
|
||||
{
|
||||
if (iPage != aPage) {
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
iPage = aPage;
|
||||
HDEBUG(iPage);
|
||||
const BooksPos pos = iModel->pageMark(iPage);
|
||||
if (iPageMark != pos) {
|
||||
iPageMark = pos;
|
||||
resetView();
|
||||
}
|
||||
resetView();
|
||||
Q_EMIT pageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::setLeftMargin(int aMargin)
|
||||
{
|
||||
if (iMargins.iLeft != aMargin) {
|
||||
iMargins.iLeft = aMargin;
|
||||
HDEBUG(aMargin);
|
||||
resetView();
|
||||
Q_EMIT leftMarginChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::setRightMargin(int aMargin)
|
||||
{
|
||||
if (iMargins.iRight != aMargin) {
|
||||
iMargins.iRight = aMargin;
|
||||
HDEBUG(aMargin);
|
||||
resetView();
|
||||
Q_EMIT rightMarginChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::setTopMargin(int aMargin)
|
||||
{
|
||||
if (iMargins.iTop != aMargin) {
|
||||
iMargins.iTop = aMargin;
|
||||
HDEBUG(aMargin);
|
||||
resetView();
|
||||
Q_EMIT topMarginChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::setBottomMargin(int aMargin)
|
||||
{
|
||||
if (iMargins.iBottom != aMargin) {
|
||||
iMargins.iBottom = aMargin;
|
||||
HDEBUG(aMargin);
|
||||
resetView();
|
||||
Q_EMIT bottomMarginChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::paint(QPainter* aPainter)
|
||||
{
|
||||
if (!iImage.isNull()) {
|
||||
HDEBUG("page" << iPage);
|
||||
aPainter->drawImage(0, 0, *iImage);
|
||||
iEmpty = false;
|
||||
} else if (iPage >= 0 && iPageMark.valid()) {
|
||||
if (!iPaintRequest) {
|
||||
iPaintRequest = true;
|
||||
HDEBUG("page" << iPage << "(scheduled)");
|
||||
scheduleRepaint();
|
||||
} else {
|
||||
HDEBUG("page" << iPage << "(not yet ready)");
|
||||
}
|
||||
iEmpty = true;
|
||||
} else {
|
||||
HDEBUG("page" << iPage << "(empty)");
|
||||
iEmpty = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool BooksPageWidget::loading() const
|
||||
{
|
||||
return iPage >= 0 && iResetTask && iRenderTask;
|
||||
}
|
||||
|
||||
void BooksPageWidget::resetView()
|
||||
{
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
if (iResetTask) {
|
||||
iResetTask->release(this);
|
||||
iResetTask = NULL;
|
||||
}
|
||||
iData.reset();
|
||||
if (iPage >= 0 && iPageMark.valid() &&
|
||||
width() > 0 && height() > 0 && iModel) {
|
||||
shared_ptr<ZLTextModel> textModel = iModel->bookTextModel();
|
||||
if (!textModel.isNull()) {
|
||||
iResetTask = new ResetTask(textModel, iTextStyle,
|
||||
width(), height(), iMargins, iPageMark);
|
||||
iTaskQueue->submit(iResetTask, this, SLOT(onResetTaskDone()));
|
||||
cancelRepaint();
|
||||
}
|
||||
}
|
||||
if (!iResetTask && !iEmpty) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::cancelRepaint()
|
||||
{
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
if (iRenderTask) {
|
||||
iRenderTask->release(this);
|
||||
iRenderTask = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::scheduleRepaint()
|
||||
{
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
cancelRepaint();
|
||||
if (width() > 0 && height() > 0 && !iData.isNull()) {
|
||||
iRenderTask = new RenderTask(iData, width(), height());
|
||||
iTaskQueue->submit(iRenderTask, this, SLOT(onRenderTaskDone()));
|
||||
} else {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::onResetTaskDone()
|
||||
{
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
HASSERT(sender() == iResetTask);
|
||||
iData = iResetTask->iData;
|
||||
iResetTask->iData = NULL;
|
||||
iResetTask->release(this);
|
||||
iResetTask = NULL;
|
||||
if (iPaintRequest) {
|
||||
scheduleRepaint();
|
||||
} else {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::onRenderTaskDone()
|
||||
{
|
||||
BooksLoadingSignalBlocker block(this);
|
||||
HASSERT(sender() == iRenderTask);
|
||||
iImage = iRenderTask->iImage;
|
||||
iRenderTask->release(this);
|
||||
iRenderTask = NULL;
|
||||
iPaintRequest = false;
|
||||
update();
|
||||
}
|
||||
|
||||
void BooksPageWidget::updateSize()
|
||||
{
|
||||
HDEBUG(QSize(width(), height()));
|
||||
resetView();
|
||||
}
|
||||
|
||||
void BooksPageWidget::onWidthChanged()
|
||||
{
|
||||
const int w = width();
|
||||
HDEBUG(w);
|
||||
// Width change will probably be followed by height change
|
||||
iResizeTimer->start();
|
||||
}
|
||||
|
||||
void BooksPageWidget::onHeightChanged()
|
||||
{
|
||||
const int h = height();
|
||||
HDEBUG(h);
|
||||
if (iResizeTimer->isActive()) {
|
||||
// Height is usually changed after width, repaint right away
|
||||
iResizeTimer->stop();
|
||||
updateSize();
|
||||
} else {
|
||||
iResizeTimer->start();
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPageWidget::onResizeTimeout()
|
||||
{
|
||||
// This can only happen if only width or height has changed. Normally,
|
||||
// width change is followed by height change and view is reset from the
|
||||
// setHeight() method
|
||||
updateSize();
|
||||
}
|
142
app/src/BooksPageWidget.h
Normal file
142
app/src/BooksPageWidget.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_PAGE_WIDGET_H
|
||||
#define BOOKS_PAGE_WIDGET_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
#include "BooksTask.h"
|
||||
#include "BooksTaskQueue.h"
|
||||
#include "BooksSettings.h"
|
||||
#include "BooksBookModel.h"
|
||||
#include "BooksPos.h"
|
||||
#include "BooksPaintContext.h"
|
||||
#include "BooksLoadingProperty.h"
|
||||
|
||||
#include "ZLTextStyle.h"
|
||||
|
||||
#include <QQuickPaintedItem>
|
||||
#include <QTimer>
|
||||
|
||||
class BooksPageWidget: public QQuickPaintedItem, private BooksLoadingProperty
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
|
||||
Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged)
|
||||
Q_PROPERTY(int leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
|
||||
Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
|
||||
Q_PROPERTY(int topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
|
||||
Q_PROPERTY(int bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
|
||||
Q_PROPERTY(BooksBookModel* model READ model WRITE setModel NOTIFY modelChanged)
|
||||
Q_PROPERTY(BooksSettings* settings READ settings WRITE setSettings NOTIFY settingsChanged)
|
||||
|
||||
public:
|
||||
class Data;
|
||||
|
||||
BooksPageWidget(QQuickItem* aParent = NULL);
|
||||
~BooksPageWidget();
|
||||
|
||||
bool loading() const;
|
||||
|
||||
int page() const { return iPage; }
|
||||
void setPage(int aPage);
|
||||
|
||||
BooksBookModel* model() const { return iModel; }
|
||||
void setModel(BooksBookModel* aModel);
|
||||
|
||||
BooksSettings* settings() const { return iSettings; }
|
||||
void setSettings(BooksSettings* aSettings);
|
||||
|
||||
int leftMargin() const { return iMargins.iLeft; }
|
||||
int rightMargin() const { return iMargins.iRight; }
|
||||
int topMargin() const { return iMargins.iTop; }
|
||||
int bottomMargin() const { return iMargins.iBottom; }
|
||||
|
||||
void setLeftMargin(int aMargin);
|
||||
void setRightMargin(int aMargin);
|
||||
void setTopMargin(int aMargin);
|
||||
void setBottomMargin(int aMargin);
|
||||
|
||||
BooksMargins margins() const { return iMargins; }
|
||||
shared_ptr<ZLTextStyle> textStyle() const { return iTextStyle; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void loadingChanged();
|
||||
void pageChanged();
|
||||
void modelChanged();
|
||||
void settingsChanged();
|
||||
void leftMarginChanged();
|
||||
void rightMarginChanged();
|
||||
void topMarginChanged();
|
||||
void bottomMarginChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onWidthChanged();
|
||||
void onHeightChanged();
|
||||
void onResizeTimeout();
|
||||
void onBookModelChanged();
|
||||
void onBookModelDestroyed();
|
||||
void onBookModelPageMarksChanged();
|
||||
void onBookModelLoadingChanged();
|
||||
void onTextStyleChanged();
|
||||
void onResetTaskDone();
|
||||
void onRenderTaskDone();
|
||||
|
||||
private:
|
||||
void paint(QPainter *painter);
|
||||
void updateSize();
|
||||
void resetView();
|
||||
void scheduleRepaint();
|
||||
void cancelRepaint();
|
||||
|
||||
private:
|
||||
class ResetTask;
|
||||
class RenderTask;
|
||||
|
||||
shared_ptr<BooksTaskQueue> iTaskQueue;
|
||||
shared_ptr<ZLTextStyle> iTextStyle;
|
||||
BooksPos iPageMark;
|
||||
QTimer* iResizeTimer;
|
||||
BooksBookModel* iModel;
|
||||
BooksSettings* iSettings;
|
||||
BooksMargins iMargins;
|
||||
shared_ptr<Data> iData;
|
||||
shared_ptr<QImage> iImage;
|
||||
ResetTask* iResetTask;
|
||||
RenderTask* iRenderTask;
|
||||
bool iPaintRequest;
|
||||
bool iEmpty;
|
||||
int iPage;
|
||||
};
|
||||
|
||||
#endif // BOOKS_PAGE_WIDGET_H
|
257
app/src/BooksPaintContext.cpp
Normal file
257
app/src/BooksPaintContext.cpp
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksPaintContext.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include "ZLImage.h"
|
||||
#include "image/ZLQtImageManager.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QFontMetrics>
|
||||
#include <QFontDatabase>
|
||||
#include <QImage>
|
||||
|
||||
static const std::string HELVETICA = "Helvetica";
|
||||
|
||||
BooksPaintContext::BooksPaintContext() :
|
||||
iPainter(NULL), iWidth(0), iHeight(0),
|
||||
iSpaceWidth(0), iDescent(0)
|
||||
{
|
||||
}
|
||||
|
||||
BooksPaintContext::BooksPaintContext(int aWidth, int aHeight) :
|
||||
iPainter(NULL), iWidth(aWidth), iHeight(aHeight),
|
||||
iSpaceWidth(0), iDescent(0)
|
||||
{
|
||||
}
|
||||
|
||||
BooksPaintContext::~BooksPaintContext()
|
||||
{
|
||||
}
|
||||
|
||||
void BooksPaintContext::beginPaint(QPainter *aPainter)
|
||||
{
|
||||
iPainter = aPainter;
|
||||
iPainter->setFont(iFont);
|
||||
}
|
||||
|
||||
void BooksPaintContext::endPaint()
|
||||
{
|
||||
iPainter = NULL;
|
||||
}
|
||||
|
||||
void BooksPaintContext::fillFamiliesList(std::vector<std::string> &families) const
|
||||
{
|
||||
QFontDatabase db;
|
||||
const QStringList qFamilies = db.families();
|
||||
bool helveticaFlag = false;
|
||||
for (QStringList::ConstIterator it = qFamilies.begin(); it != qFamilies.end(); ++it) {
|
||||
std::string family = it->toUtf8().constData();
|
||||
helveticaFlag |= (family == HELVETICA);
|
||||
families.push_back(family);
|
||||
}
|
||||
if (!helveticaFlag) {
|
||||
families.push_back(HELVETICA);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string BooksPaintContext::realFontFamilyName(std::string &fontFamily) const
|
||||
{
|
||||
QString fullName = QFontInfo(QFont(QString::fromUtf8(fontFamily.c_str()))).family();
|
||||
if (fullName.isNull() || fullName.isEmpty()) {
|
||||
return HELVETICA;
|
||||
}
|
||||
return fullName.toStdString();
|
||||
}
|
||||
|
||||
void BooksPaintContext::setFont(const std::string& family, int size, bool bold, bool italic)
|
||||
{
|
||||
bool fontChanged = false;
|
||||
|
||||
if (!family.empty()) {
|
||||
QString qtFamily(QString::fromStdString(family));
|
||||
if (iFont.family() != qtFamily) {
|
||||
iFont.setFamily(qtFamily);
|
||||
fontChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (iFont.pointSize() != size) {
|
||||
iFont.setPointSize(size);
|
||||
fontChanged = true;
|
||||
}
|
||||
|
||||
if ((iFont.weight() != (bold ? QFont::Bold : QFont::Normal))) {
|
||||
iFont.setWeight(bold ? QFont::Bold : QFont::Normal);
|
||||
fontChanged = true;
|
||||
}
|
||||
|
||||
if (iFont.italic() != italic) {
|
||||
iFont.setItalic(italic);
|
||||
fontChanged = true;
|
||||
}
|
||||
|
||||
if (fontChanged) {
|
||||
QFontMetrics fontMetrics(iFont);
|
||||
iSpaceWidth = fontMetrics.width(QString(" "));
|
||||
iDescent = fontMetrics.descent();
|
||||
if (iPainter) {
|
||||
iPainter->setFont(iFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPaintContext::setColor(ZLColor color, LineStyle style)
|
||||
{
|
||||
if (iPainter) {
|
||||
iPainter->setPen(QPen(qtColor(color), 1, (style == SOLID_LINE) ?
|
||||
Qt::SolidLine : Qt::DashLine));
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPaintContext::setFillColor(ZLColor color, FillStyle style)
|
||||
{
|
||||
if (iPainter) {
|
||||
iPainter->setBrush(QBrush(qtColor(color), (style == SOLID_FILL) ?
|
||||
Qt::SolidPattern : Qt::Dense4Pattern));
|
||||
}
|
||||
}
|
||||
|
||||
int BooksPaintContext::stringWidth(const char *str, int len, bool) const
|
||||
{
|
||||
QFontMetrics fontMetrics(iFont);
|
||||
return fontMetrics.width(QString::fromUtf8(str, len));
|
||||
}
|
||||
|
||||
int BooksPaintContext::spaceWidth() const
|
||||
{
|
||||
return iSpaceWidth;
|
||||
}
|
||||
|
||||
int BooksPaintContext::descent() const
|
||||
{
|
||||
return iDescent;
|
||||
}
|
||||
|
||||
int BooksPaintContext::stringHeight() const
|
||||
{
|
||||
return iFont.pointSize() + 2;
|
||||
}
|
||||
|
||||
void BooksPaintContext::drawString(int x, int y, const char* str, int len, bool rtl)
|
||||
{
|
||||
if (iPainter) {
|
||||
QString qStr = QString::fromUtf8(str, len);
|
||||
iPainter->setLayoutDirection(rtl ? Qt::RightToLeft : Qt::LeftToRight);
|
||||
iPainter->drawText(x, y, qStr);
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPaintContext::drawImage(int x, int y, const ZLImageData& image)
|
||||
{
|
||||
if (iPainter) {
|
||||
const QImage* qImage = ((ZLQtImageData&)image).image();
|
||||
if (qImage) {
|
||||
iPainter->drawImage(x, y - image.height(), *qImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPaintContext::drawImage(int x, int y, const ZLImageData& image,
|
||||
int width, int height, ScalingType type)
|
||||
{
|
||||
if (iPainter) {
|
||||
const QImage* qImage = ((ZLQtImageData&)image).image();
|
||||
if (qImage) {
|
||||
const QImage scaled = qImage->scaled(
|
||||
QSize(imageWidth(image, width, height, type),
|
||||
imageHeight(image, width, height, type)),
|
||||
Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation
|
||||
);
|
||||
iPainter->drawImage(x, y - scaled.height(), scaled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPaintContext::drawLine(int x0, int y0, int x1, int y1)
|
||||
{
|
||||
if (iPainter) {
|
||||
iPainter->drawPoint(x0, y0);
|
||||
iPainter->drawLine(x0, y0, x1, y1);
|
||||
iPainter->drawPoint(x1, y1);
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPaintContext::fillRectangle(int x0, int y0, int x1, int y1)
|
||||
{
|
||||
if (iPainter) {
|
||||
if (x1 < x0) {
|
||||
int tmp = x1;
|
||||
x1 = x0;
|
||||
x0 = tmp;
|
||||
}
|
||||
if (y1 < y0) {
|
||||
int tmp = y1;
|
||||
y1 = y0;
|
||||
y0 = tmp;
|
||||
}
|
||||
iPainter->fillRect(x0, y0, x1-x0+1, y1-y0+1, iPainter->brush());
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPaintContext::drawFilledCircle(int x, int y, int r)
|
||||
{
|
||||
if (iPainter) {
|
||||
iPainter->drawEllipse(x - r, y - r, 2 * r + 1, 2 * r + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void BooksPaintContext::clear(ZLColor aColor)
|
||||
{
|
||||
if (iPainter) {
|
||||
iPainter->fillRect(0, 0, iWidth, iHeight, qtColor(aColor));
|
||||
}
|
||||
}
|
||||
|
||||
int BooksPaintContext::width() const
|
||||
{
|
||||
return iWidth;
|
||||
}
|
||||
|
||||
int BooksPaintContext::height() const
|
||||
{
|
||||
return iHeight;
|
||||
}
|
112
app/src/BooksPaintContext.h
Normal file
112
app/src/BooksPaintContext.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_PAINT_CONTEXT_H
|
||||
#define BOOKS_PAINT_CONTEXT_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
|
||||
#include "ZLPaintContext.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QSize>
|
||||
#include <QColor>
|
||||
|
||||
class QPainter;
|
||||
|
||||
class BooksPaintContext : public ZLPaintContext {
|
||||
|
||||
public:
|
||||
BooksPaintContext(int aWidth, int aHeight);
|
||||
BooksPaintContext();
|
||||
~BooksPaintContext();
|
||||
|
||||
void setWidth(int aWidth);
|
||||
void setHeight(int aHeight);
|
||||
void setSize(int aWidth, int aHeight);
|
||||
bool isEmpty() const;
|
||||
QSize size() const;
|
||||
|
||||
// ZLPaintContext
|
||||
void beginPaint(QPainter* painter);
|
||||
void endPaint();
|
||||
|
||||
int width() const;
|
||||
int height() const;
|
||||
|
||||
void clear(ZLColor color);
|
||||
|
||||
void fillFamiliesList(std::vector<std::string>& families) const;
|
||||
const std::string realFontFamilyName(std::string& fontFamily) const;
|
||||
|
||||
void setFont(const std::string& family, int size, bool bold, bool italic);
|
||||
void setColor(ZLColor color, LineStyle style);
|
||||
void setFillColor(ZLColor color, FillStyle style);
|
||||
|
||||
int stringWidth(const char* str, int len, bool rtl) const;
|
||||
int spaceWidth() const;
|
||||
int stringHeight() const;
|
||||
int descent() const;
|
||||
void drawString(int x, int y, const char* str, int len, bool rtl);
|
||||
|
||||
void drawImage(int x, int y, const ZLImageData& image);
|
||||
void drawImage(int x, int y, const ZLImageData& image, int width, int height, ScalingType type);
|
||||
|
||||
void drawLine(int x0, int y0, int x1, int y1);
|
||||
void fillRectangle(int x0, int y0, int x1, int y1);
|
||||
void drawFilledCircle(int x, int y, int r);
|
||||
|
||||
private:
|
||||
QPainter* iPainter;
|
||||
int iWidth;
|
||||
int iHeight;
|
||||
mutable int iSpaceWidth;
|
||||
int iDescent;
|
||||
QFont iFont;
|
||||
};
|
||||
|
||||
inline void BooksPaintContext::setWidth(int aWidth)
|
||||
{ iWidth = aWidth; }
|
||||
inline void BooksPaintContext::setHeight(int aHeight)
|
||||
{ iHeight = aHeight; }
|
||||
inline void BooksPaintContext::setSize(int aWidth, int aHeight)
|
||||
{ iWidth = aWidth; iHeight = aHeight; }
|
||||
inline bool BooksPaintContext::isEmpty() const
|
||||
{ return (iWidth <= 0 || iHeight <= 0); }
|
||||
inline QSize BooksPaintContext::size() const
|
||||
{ return QSize(iWidth, iHeight); }
|
||||
|
||||
inline QColor qtColor(const ZLColor& aColor)
|
||||
{ return QColor(aColor.Red, aColor.Green, aColor.Blue); }
|
||||
|
||||
#endif /* BOOKS_PAINT_CONTEXT_H */
|
167
app/src/BooksPos.h
Normal file
167
app/src/BooksPos.h
Normal file
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_POSITION_H
|
||||
#define BOOKS_POSITION_H
|
||||
|
||||
#include <QVariant>
|
||||
#include <QDebug>
|
||||
#include <QList>
|
||||
|
||||
|
||||
#include "ZLTextParagraphCursor.h"
|
||||
|
||||
struct BooksPos {
|
||||
int iParagraphIndex, iElementIndex, iCharIndex;
|
||||
|
||||
typedef QList<BooksPos> List;
|
||||
typedef QList<BooksPos>::iterator Iterator;
|
||||
typedef QList<BooksPos>::const_iterator ConstIterator;
|
||||
|
||||
BooksPos() :
|
||||
iParagraphIndex(-1),
|
||||
iElementIndex(-1),
|
||||
iCharIndex(-1) {}
|
||||
|
||||
BooksPos(const ZLTextWordCursor& aCursor) :
|
||||
iElementIndex(aCursor.elementIndex()),
|
||||
iCharIndex(aCursor.charIndex())
|
||||
{
|
||||
ZLTextParagraphCursorPtr ptr(aCursor.paragraphCursorPtr());
|
||||
iParagraphIndex = ptr.isNull() ? 0 : ptr->index();
|
||||
}
|
||||
|
||||
BooksPos(int aParagraphIndex, int aElementIndex, int aCharIndex) :
|
||||
iParagraphIndex(aParagraphIndex),
|
||||
iElementIndex(aElementIndex),
|
||||
iCharIndex(aCharIndex) {}
|
||||
|
||||
BooksPos(const BooksPos& aPos) :
|
||||
iParagraphIndex(aPos.iParagraphIndex),
|
||||
iElementIndex(aPos.iElementIndex),
|
||||
iCharIndex(aPos.iCharIndex) {}
|
||||
|
||||
void invalidate()
|
||||
{
|
||||
iParagraphIndex = iElementIndex = iCharIndex = -1;
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return iParagraphIndex >= 0 && iElementIndex >= 0 && iCharIndex >= 0;
|
||||
}
|
||||
|
||||
QVariant toVariant() const
|
||||
{
|
||||
QVariantList list;
|
||||
list.append(iParagraphIndex);
|
||||
list.append(iElementIndex);
|
||||
list.append(iCharIndex);
|
||||
return QVariant::fromValue(list);
|
||||
}
|
||||
|
||||
static BooksPos fromVariant(QVariant aVariant)
|
||||
{
|
||||
if (aVariant.isValid()) {
|
||||
QVariantList list = aVariant.toList();
|
||||
if (list.count() == 3) {
|
||||
bool ok = false;
|
||||
int paraIndex = list.at(0).toInt(&ok);
|
||||
if (ok) {
|
||||
int elemIndex = list.at(1).toInt(&ok);
|
||||
if (ok) {
|
||||
int charIndex = list.at(2).toInt(&ok);
|
||||
if (ok) {
|
||||
return BooksPos(paraIndex, elemIndex, charIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return BooksPos();
|
||||
}
|
||||
|
||||
const BooksPos& operator = (const BooksPos& aPos)
|
||||
{
|
||||
iParagraphIndex = aPos.iParagraphIndex;
|
||||
iElementIndex = aPos.iElementIndex;
|
||||
iCharIndex = aPos.iCharIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator < (const BooksPos& aPos) const
|
||||
{
|
||||
return (iParagraphIndex < aPos.iParagraphIndex) ? true :
|
||||
(iParagraphIndex > aPos.iParagraphIndex) ? false :
|
||||
(iElementIndex < aPos.iElementIndex) ? true :
|
||||
(iElementIndex > aPos.iElementIndex) ? false :
|
||||
(iCharIndex < aPos.iCharIndex) ? true :
|
||||
(iCharIndex > aPos.iCharIndex) ? false : true;
|
||||
}
|
||||
|
||||
bool operator > (const BooksPos& aPos) const
|
||||
{
|
||||
return (aPos < *this);
|
||||
}
|
||||
|
||||
bool operator <= (const BooksPos& aPos) const
|
||||
{
|
||||
return !(*this > aPos);
|
||||
}
|
||||
|
||||
bool operator >= (const BooksPos& aPos) const
|
||||
{
|
||||
return !(*this < aPos);
|
||||
}
|
||||
|
||||
bool operator == (const BooksPos& aPos) const
|
||||
{
|
||||
return iParagraphIndex == aPos.iParagraphIndex &&
|
||||
iElementIndex == aPos.iElementIndex &&
|
||||
iCharIndex == aPos.iCharIndex;
|
||||
}
|
||||
|
||||
bool operator != (const BooksPos& aPos) const
|
||||
{
|
||||
return iParagraphIndex != aPos.iParagraphIndex ||
|
||||
iElementIndex != aPos.iElementIndex ||
|
||||
iCharIndex != aPos.iCharIndex;
|
||||
}
|
||||
};
|
||||
|
||||
inline QDebug& operator<<(QDebug& aDebug, const BooksPos& aPosition)
|
||||
{ aDebug << qPrintable(QString("BooksPos(%1,%2,%3)").
|
||||
arg(aPosition.iParagraphIndex).arg(aPosition.iElementIndex).
|
||||
arg(aPosition.iCharIndex)); return aDebug.maybeSpace(); }
|
||||
|
||||
#endif /* BOOKS_POSITION_H */
|
90
app/src/BooksSaveTimer.cpp
Normal file
90
app/src/BooksSaveTimer.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksSaveTimer.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
|
||||
#define BOOKS_DEFAULT_INACTIVITY_TIMEOUT (1000)
|
||||
#define BOOKS_DEFAULT_MANDATORY_SAVE_TIMEOUT (30000)
|
||||
|
||||
BooksSaveTimer::BooksSaveTimer(QObject* aParent) :
|
||||
QObject(aParent),
|
||||
iInactivityTimer(new QTimer(this)),
|
||||
iMandatarySaveTimer(new QTimer(this)),
|
||||
iSaveRequested(false)
|
||||
{
|
||||
connect(qApp, SIGNAL(aboutToQuit()), SLOT(onAboutToQuit()));
|
||||
|
||||
iInactivityTimer->setInterval(BOOKS_DEFAULT_INACTIVITY_TIMEOUT);
|
||||
iInactivityTimer->setSingleShot(true);
|
||||
connect(iInactivityTimer, SIGNAL(timeout()), SLOT(onTimeout()));
|
||||
|
||||
iMandatarySaveTimer->setInterval(BOOKS_DEFAULT_MANDATORY_SAVE_TIMEOUT);
|
||||
iMandatarySaveTimer->setSingleShot(true);
|
||||
connect(iMandatarySaveTimer, SIGNAL(timeout()), SLOT(onTimeout()));
|
||||
}
|
||||
|
||||
void BooksSaveTimer::requestSave()
|
||||
{
|
||||
if (!iMandatarySaveTimer->isActive()) {
|
||||
iMandatarySaveTimer->start();
|
||||
}
|
||||
iInactivityTimer->start();
|
||||
}
|
||||
|
||||
void BooksSaveTimer::cancelSave()
|
||||
{
|
||||
iMandatarySaveTimer->stop();
|
||||
iInactivityTimer->stop();
|
||||
}
|
||||
|
||||
bool BooksSaveTimer::saveRequested() const
|
||||
{
|
||||
return iMandatarySaveTimer->isActive();
|
||||
}
|
||||
|
||||
void BooksSaveTimer::onTimeout()
|
||||
{
|
||||
iMandatarySaveTimer->stop();
|
||||
iInactivityTimer->stop();
|
||||
Q_EMIT save();
|
||||
}
|
||||
|
||||
void BooksSaveTimer::onAboutToQuit()
|
||||
{
|
||||
if (saveRequested()) {
|
||||
onTimeout();
|
||||
}
|
||||
}
|
65
app/src/BooksSaveTimer.h
Normal file
65
app/src/BooksSaveTimer.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_SAVE_TIMER_H
|
||||
#define BOOKS_SAVE_TIMER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QTimer;
|
||||
|
||||
class BooksSaveTimer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BooksSaveTimer(QObject* aParent = NULL);
|
||||
|
||||
void requestSave();
|
||||
void cancelSave();
|
||||
bool saveRequested() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void save();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onAboutToQuit();
|
||||
void onTimeout();
|
||||
|
||||
private:
|
||||
QTimer* iInactivityTimer;
|
||||
QTimer* iMandatarySaveTimer;
|
||||
bool iSaveRequested;
|
||||
};
|
||||
|
||||
#endif // BOOKS_SAVE_TIMER_H
|
305
app/src/BooksSettings.cpp
Normal file
305
app/src/BooksSettings.cpp
Normal file
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksSettings.h"
|
||||
#include "BooksTextStyle.h"
|
||||
#include "BooksBook.h"
|
||||
#include "BooksDefs.h"
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include <MGConfItem>
|
||||
|
||||
#define DCONF_PATH "/apps/" BOOKS_APP_NAME "/"
|
||||
#define KEY_FONT_SIZE "fontSize"
|
||||
#define KEY_PAGE_DETAILS "pageDetails"
|
||||
#define KEY_CURRENT_BOOK "currentBook"
|
||||
#define DEFAULT_FONT_SIZE 0
|
||||
#define DEFAULT_PAGE_DETAILS 0
|
||||
#define DEFAULT_CURRENT_BOOK QString()
|
||||
|
||||
// ==========================================================================
|
||||
// BooksSettings::TextStyle
|
||||
// ==========================================================================
|
||||
|
||||
class BooksSettings::TextStyle : public ZLTextStyle
|
||||
{
|
||||
public:
|
||||
TextStyle(int aFontSizeModifier) :
|
||||
iDefaultStyle(BooksTextStyle::defaults()),
|
||||
iFontSize(iDefaultStyle->fontSize() + 2*aFontSizeModifier)
|
||||
{ HDEBUG(iFontSize); }
|
||||
|
||||
bool isDecorated() const;
|
||||
|
||||
const std::string &fontFamily() const;
|
||||
|
||||
int fontSize() const;
|
||||
bool bold() const;
|
||||
bool italic() const;
|
||||
|
||||
const std::string &colorStyle() const;
|
||||
|
||||
short spaceBefore(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
||||
short spaceAfter(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
||||
short lineStartIndent(const ZLTextStyleEntry::Metrics& aMetrics, bool aRtl) const;
|
||||
short lineEndIndent(const ZLTextStyleEntry::Metrics& aMetrics, bool aRtl) const;
|
||||
short firstLineIndentDelta(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
||||
int verticalShift() const;
|
||||
|
||||
ZLTextAlignmentType alignment() const;
|
||||
|
||||
double lineSpace() const;
|
||||
bool allowHyphenations() const;
|
||||
|
||||
private:
|
||||
shared_ptr<ZLTextStyle> iDefaultStyle;
|
||||
int iFontSize;
|
||||
};
|
||||
|
||||
const std::string&
|
||||
BooksSettings::TextStyle::colorStyle() const
|
||||
{
|
||||
return iDefaultStyle->colorStyle();
|
||||
}
|
||||
|
||||
bool
|
||||
BooksSettings::TextStyle::isDecorated() const
|
||||
{
|
||||
return iDefaultStyle->isDecorated();
|
||||
}
|
||||
|
||||
const std::string&
|
||||
BooksSettings::TextStyle::fontFamily() const
|
||||
{
|
||||
return iDefaultStyle->fontFamily();
|
||||
}
|
||||
|
||||
int
|
||||
BooksSettings::TextStyle::fontSize() const
|
||||
{
|
||||
return iFontSize;
|
||||
}
|
||||
|
||||
bool
|
||||
BooksSettings::TextStyle::bold() const
|
||||
{
|
||||
return iDefaultStyle->bold();
|
||||
}
|
||||
|
||||
bool
|
||||
BooksSettings::TextStyle::italic() const
|
||||
{
|
||||
return iDefaultStyle->italic();
|
||||
}
|
||||
|
||||
short
|
||||
BooksSettings::TextStyle::spaceBefore(
|
||||
const ZLTextStyleEntry::Metrics& aMetrics) const
|
||||
{
|
||||
return iDefaultStyle->spaceBefore(aMetrics);
|
||||
}
|
||||
|
||||
short
|
||||
BooksSettings::TextStyle::spaceAfter(
|
||||
const ZLTextStyleEntry::Metrics& aMetrics) const
|
||||
{
|
||||
return iDefaultStyle->spaceAfter(aMetrics);
|
||||
}
|
||||
|
||||
short
|
||||
BooksSettings::TextStyle::lineStartIndent(
|
||||
const ZLTextStyleEntry::Metrics& aMetrics,
|
||||
bool aRtl) const
|
||||
{
|
||||
return iDefaultStyle->lineStartIndent(aMetrics, aRtl);
|
||||
}
|
||||
|
||||
short
|
||||
BooksSettings::TextStyle::lineEndIndent(
|
||||
const ZLTextStyleEntry::Metrics& aMetrics,
|
||||
bool aRtl) const
|
||||
{
|
||||
return iDefaultStyle->lineEndIndent(aMetrics, aRtl);
|
||||
}
|
||||
|
||||
short
|
||||
BooksSettings::TextStyle::firstLineIndentDelta(
|
||||
const ZLTextStyleEntry::Metrics& aMetrics) const
|
||||
{
|
||||
return iDefaultStyle->firstLineIndentDelta(aMetrics);
|
||||
}
|
||||
|
||||
int
|
||||
BooksSettings::TextStyle::verticalShift() const
|
||||
{
|
||||
return iDefaultStyle->verticalShift();
|
||||
}
|
||||
|
||||
ZLTextAlignmentType
|
||||
BooksSettings::TextStyle::alignment() const
|
||||
{
|
||||
return iDefaultStyle->alignment();
|
||||
}
|
||||
|
||||
double
|
||||
BooksSettings::TextStyle::lineSpace() const
|
||||
{
|
||||
return iDefaultStyle->lineSpace();
|
||||
}
|
||||
|
||||
bool
|
||||
BooksSettings::TextStyle::allowHyphenations() const
|
||||
{
|
||||
return iDefaultStyle->allowHyphenations();
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksSettings
|
||||
// ==========================================================================
|
||||
|
||||
BooksSettings::BooksSettings(QObject* aParent) :
|
||||
QObject(aParent),
|
||||
iFontSize(new MGConfItem(DCONF_PATH KEY_FONT_SIZE, this)),
|
||||
iPageDetails(new MGConfItem(DCONF_PATH KEY_PAGE_DETAILS, this)),
|
||||
iCurrentBookPath(new MGConfItem(DCONF_PATH KEY_CURRENT_BOOK, this)),
|
||||
iCurrentBook(NULL)
|
||||
{
|
||||
iTextStyle = new TextStyle(fontSize());
|
||||
updateCurrentBook();
|
||||
connect(iFontSize, SIGNAL(valueChanged()), SLOT(onFontSizeValueChanged()));
|
||||
connect(iPageDetails, SIGNAL(valueChanged()), SIGNAL(pageDetailsChanged()));
|
||||
connect(iCurrentBookPath, SIGNAL(valueChanged()), SLOT(onCurrentBookPathChanged()));
|
||||
}
|
||||
|
||||
int
|
||||
BooksSettings::fontSize() const
|
||||
{
|
||||
return iFontSize->value(DEFAULT_FONT_SIZE).toInt();
|
||||
}
|
||||
|
||||
void
|
||||
BooksSettings::setFontSize(
|
||||
int aValue)
|
||||
{
|
||||
HDEBUG(aValue);
|
||||
iFontSize->set(aValue);
|
||||
}
|
||||
|
||||
void
|
||||
BooksSettings::onFontSizeValueChanged()
|
||||
{
|
||||
const int newSize = fontSize();
|
||||
HDEBUG(newSize);
|
||||
iTextStyle = new TextStyle(newSize);
|
||||
Q_EMIT fontSizeChanged();
|
||||
Q_EMIT textStyleChanged();
|
||||
}
|
||||
|
||||
int
|
||||
BooksSettings::pageDetails() const
|
||||
{
|
||||
return iPageDetails->value(DEFAULT_PAGE_DETAILS).toInt();
|
||||
}
|
||||
|
||||
void
|
||||
BooksSettings::setPageDetails(
|
||||
int aValue)
|
||||
{
|
||||
HDEBUG(aValue);
|
||||
iPageDetails->set(aValue);
|
||||
}
|
||||
|
||||
QObject*
|
||||
BooksSettings::currentBook() const
|
||||
{
|
||||
return iCurrentBook;
|
||||
}
|
||||
|
||||
void
|
||||
BooksSettings::setCurrentBook(QObject* aBook)
|
||||
{
|
||||
BooksBook* book = qobject_cast<BooksBook*>(aBook);
|
||||
if (iCurrentBook != book) {
|
||||
if (iCurrentBook) iCurrentBook->release();
|
||||
if (book) {
|
||||
HDEBUG(book->path());
|
||||
(iCurrentBook = book)->retain();
|
||||
iCurrentBookPath->set(book->path());
|
||||
} else {
|
||||
iCurrentBook = NULL;
|
||||
iCurrentBookPath->set(QString());
|
||||
}
|
||||
Q_EMIT currentBookChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
BooksSettings::updateCurrentBook()
|
||||
{
|
||||
QString path = iCurrentBookPath->value(DEFAULT_CURRENT_BOOK).toString();
|
||||
if (path.isEmpty()) {
|
||||
if (iCurrentBook) {
|
||||
iCurrentBook->release();
|
||||
iCurrentBook = NULL;
|
||||
return true;
|
||||
}
|
||||
} else if (!iCurrentBook || iCurrentBook->path() != path) {
|
||||
ZLFile file(path.toStdString());
|
||||
shared_ptr<Book> book = Book::loadFromFile(file);
|
||||
if (!book.isNull()) {
|
||||
QFileInfo info(path);
|
||||
BooksStorageManager* mgr = BooksStorageManager::instance();
|
||||
BooksStorage storage = mgr->storageForPath(info.path());
|
||||
if (storage.isValid()) {
|
||||
if (iCurrentBook) iCurrentBook->release();
|
||||
iCurrentBook = new BooksBook(storage, book);
|
||||
iCurrentBook->requestCoverImage();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (iCurrentBook) {
|
||||
iCurrentBook->release();
|
||||
iCurrentBook = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
BooksSettings::onCurrentBookPathChanged()
|
||||
{
|
||||
if (updateCurrentBook()) {
|
||||
Q_EMIT currentBookChanged();
|
||||
}
|
||||
}
|
96
app/src/BooksSettings.h
Normal file
96
app/src/BooksSettings.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_SETTINGS_H
|
||||
#define BOOKS_SETTINGS_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
#include "ZLTextStyle.h"
|
||||
#include <QtQml>
|
||||
|
||||
class MGConfItem;
|
||||
|
||||
class BooksSettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(FontSize)
|
||||
Q_PROPERTY(int fontSize READ fontSize WRITE setFontSize NOTIFY fontSizeChanged)
|
||||
Q_PROPERTY(int pageDetails READ pageDetails WRITE setPageDetails NOTIFY pageDetailsChanged)
|
||||
Q_PROPERTY(QObject* currentBook READ currentBook WRITE setCurrentBook NOTIFY currentBookChanged)
|
||||
class TextStyle;
|
||||
|
||||
public:
|
||||
enum FontSize {
|
||||
MinFontSize = -5,
|
||||
DefaultFontSize = 0,
|
||||
MaxFontSize = 5
|
||||
};
|
||||
|
||||
explicit BooksSettings(QObject* aParent = NULL);
|
||||
|
||||
int fontSize() const;
|
||||
void setFontSize(int aValue);
|
||||
|
||||
int pageDetails() const;
|
||||
void setPageDetails(int aValue);
|
||||
|
||||
shared_ptr<ZLTextStyle> textStyle() const { return iTextStyle; }
|
||||
|
||||
QObject* currentBook() const;
|
||||
void setCurrentBook(QObject* aBook);
|
||||
|
||||
signals:
|
||||
void fontSizeChanged();
|
||||
void textStyleChanged();
|
||||
void pageDetailsChanged();
|
||||
void currentBookChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onFontSizeValueChanged();
|
||||
void onCurrentBookPathChanged();
|
||||
|
||||
private:
|
||||
void updateRenderType();
|
||||
bool updateCurrentBook();
|
||||
|
||||
private:
|
||||
MGConfItem* iFontSize;
|
||||
MGConfItem* iPageDetails;
|
||||
MGConfItem* iCurrentBookPath;
|
||||
shared_ptr<ZLTextStyle> iTextStyle;
|
||||
BooksBook* iCurrentBook;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(BooksSettings)
|
||||
|
||||
#endif // BOOKS_SETTINGS_H
|
1071
app/src/BooksShelf.cpp
Normal file
1071
app/src/BooksShelf.cpp
Normal file
File diff suppressed because it is too large
Load diff
172
app/src/BooksShelf.h
Normal file
172
app/src/BooksShelf.h
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_SHELF_MODEL_H
|
||||
#define BOOKS_SHELF_MODEL_H
|
||||
|
||||
#include "BooksItem.h"
|
||||
#include "BooksStorage.h"
|
||||
#include "BooksSaveTimer.h"
|
||||
#include "BooksTask.h"
|
||||
#include "BooksTaskQueue.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
#include <QAbstractListModel>
|
||||
#include <QtQml>
|
||||
|
||||
class BooksShelf: public QAbstractListModel, public BooksItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
|
||||
Q_PROPERTY(QString path READ path NOTIFY pathChanged)
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
Q_PROPERTY(QString device READ device WRITE setDevice NOTIFY deviceChanged)
|
||||
Q_PROPERTY(QString relativePath READ relativePath WRITE setRelativePath NOTIFY relativePathChanged)
|
||||
Q_PROPERTY(bool editMode READ editMode WRITE setEditMode NOTIFY editModeChanged)
|
||||
Q_PROPERTY(bool hasDummyItem READ hasDummyItem WRITE setHasDummyItem NOTIFY hasDummyItemChanged)
|
||||
Q_PROPERTY(int dummyItemIndex READ dummyItemIndex WRITE setDummyItemIndex NOTIFY dummyItemIndexChanged)
|
||||
Q_PROPERTY(BooksBook* book READ book CONSTANT)
|
||||
|
||||
public:
|
||||
explicit BooksShelf(QObject* aParent = NULL);
|
||||
~BooksShelf();
|
||||
|
||||
Q_INVOKABLE QObject* get(int aIndex) const;
|
||||
Q_INVOKABLE bool drop(QObject* aItem);
|
||||
Q_INVOKABLE void move(int aFrom, int aTo);
|
||||
Q_INVOKABLE void remove(int aIndex);
|
||||
Q_INVOKABLE void removeAll();
|
||||
Q_INVOKABLE bool deleteRequested(int aIndex) const;
|
||||
Q_INVOKABLE void setDeleteRequested(int aIndex, bool aValue);
|
||||
Q_INVOKABLE void cancelAllDeleteRequests();
|
||||
Q_INVOKABLE void importBook(QObject* aBook);
|
||||
|
||||
bool loading() const { return iLoadTask != NULL; }
|
||||
int count() const;
|
||||
QString path() const { return iPath; }
|
||||
QString relativePath() const { return iRelativePath; }
|
||||
void setRelativePath(QString aPath);
|
||||
BooksBook* bookAt(int aIndex) const;
|
||||
|
||||
bool editMode() const { return iEditMode; }
|
||||
void setEditMode(bool aEditMode);
|
||||
|
||||
bool hasDummyItem() const { return iDummyItemIndex >= 0; }
|
||||
void setHasDummyItem(bool aHasDummyItem);
|
||||
|
||||
int dummyItemIndex() const { return iDummyItemIndex; }
|
||||
void setDummyItemIndex(int aIndex);
|
||||
|
||||
QString device() { return iStorage.device(); }
|
||||
void setDevice(QString aDevice);
|
||||
|
||||
// QAbstractListModel
|
||||
virtual QHash<int,QByteArray> roleNames() const;
|
||||
virtual int rowCount(const QModelIndex& aParent) const;
|
||||
virtual QVariant data(const QModelIndex& aIndex, int aRole) const;
|
||||
|
||||
// BooksListItem
|
||||
virtual BooksItem* retain();
|
||||
virtual void release();
|
||||
virtual QObject* object();
|
||||
virtual BooksShelf* shelf();
|
||||
virtual BooksBook* book();
|
||||
virtual QString name() const;
|
||||
virtual QString fileName() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void loadingChanged();
|
||||
void countChanged();
|
||||
void pathChanged();
|
||||
void nameChanged();
|
||||
void deviceChanged();
|
||||
void relativePathChanged();
|
||||
void editModeChanged();
|
||||
void hasDummyItemChanged();
|
||||
void dummyItemIndexChanged();
|
||||
void bookAdded(BooksBook* aBook);
|
||||
void bookRemoved(BooksBook* aBook);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onLoadTaskDone();
|
||||
void onBookFound(BooksBook* aBook);
|
||||
void onBookAccessibleChanged();
|
||||
void onBookCopyingOutChanged();
|
||||
void onBookMovedAway();
|
||||
void onCopyTaskPercentChanged();
|
||||
void onCopyTaskDone();
|
||||
void onDeleteTaskDone();
|
||||
void saveState();
|
||||
|
||||
private:
|
||||
QString stateFileName() const;
|
||||
int bookIndex(BooksBook* aBook) const;
|
||||
int itemIndex(QString aFileName, int aStartIndex = 0) const;
|
||||
bool validIndex(int aIndex) const;
|
||||
void emitDataChangedSignal(int aRow, int aRole);
|
||||
void queueStateSave();
|
||||
void loadBookList();
|
||||
void updatePath();
|
||||
void removeAllBooks();
|
||||
BooksBook* removeBook(int aIndex);
|
||||
|
||||
private:
|
||||
class Data;
|
||||
class CopyTask;
|
||||
class LoadTask;
|
||||
class ImportTask;
|
||||
class DeleteTask;
|
||||
QList<Data*> iList;
|
||||
QList<DeleteTask*> iDeleteTasks;
|
||||
LoadTask* iLoadTask;
|
||||
QString iName;
|
||||
QString iFileName;
|
||||
QString iPath;
|
||||
QString iRelativePath;
|
||||
BooksStorage iStorage;
|
||||
int iDummyItemIndex;
|
||||
bool iEditMode;
|
||||
QAtomicInt iRef;
|
||||
BooksSaveTimer* iSaveTimer;
|
||||
shared_ptr<BooksTaskQueue> iTaskQueue;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(BooksShelf)
|
||||
|
||||
inline bool BooksShelf::validIndex(int aIndex) const
|
||||
{ return aIndex >= 0 && aIndex < iList.count(); }
|
||||
|
||||
#endif // BOOKS_SHELF_MODEL_H
|
519
app/src/BooksStorage.cpp
Normal file
519
app/src/BooksStorage.cpp
Normal file
|
@ -0,0 +1,519 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksStorage.h"
|
||||
#include "BooksDefs.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include "ZLibrary.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QFile>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QFileInfo>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QSocketNotifier>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#define INTERNAL_STATE_DIR "internal"
|
||||
#define REMOVABLE_STATE_DIR "removable"
|
||||
|
||||
// ==========================================================================
|
||||
// BooksStorage::Data
|
||||
// ==========================================================================
|
||||
|
||||
class BooksStorage::Private: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Private(QString aDevice, QDir aBooksDir, bool aInternal);
|
||||
|
||||
bool isRemoved() const;
|
||||
bool equal(const Private& aData) const;
|
||||
|
||||
static QString mountPoint(QString aPath);
|
||||
static bool isMountPoint(QString aPath);
|
||||
|
||||
Q_SIGNALS:
|
||||
void removed();
|
||||
|
||||
public:
|
||||
QAtomicInt iRef;
|
||||
QString iDevice;
|
||||
QDir iBooksDir;
|
||||
QDir iConfigDir;
|
||||
bool iInternal;
|
||||
bool iPresent;
|
||||
};
|
||||
|
||||
BooksStorage::Private::Private(QString aDevice, QDir aBooksDir, bool aInternal) :
|
||||
iRef(1), iDevice(aDevice), iBooksDir(aBooksDir), iInternal(aInternal),
|
||||
iPresent(true)
|
||||
{
|
||||
QString cfgDir;
|
||||
cfgDir = QString::fromStdString(ZLibrary::ApplicationWritableDirectory());
|
||||
if (!cfgDir.endsWith('/')) cfgDir += '/';
|
||||
if (aInternal) {
|
||||
cfgDir += INTERNAL_STATE_DIR;
|
||||
QString subDir(aDevice);
|
||||
if (subDir.startsWith("/dev")) subDir.remove(0,4);
|
||||
if (!subDir.startsWith('/')) cfgDir += '/';
|
||||
cfgDir += subDir;
|
||||
} else {
|
||||
cfgDir += REMOVABLE_STATE_DIR "/";
|
||||
QString label = QDir(Private::mountPoint(aBooksDir.path())).dirName();
|
||||
if (label.isEmpty()) label = "sdcard";
|
||||
cfgDir += label;
|
||||
}
|
||||
iConfigDir.setPath(cfgDir);
|
||||
}
|
||||
|
||||
bool BooksStorage::Private::equal(const BooksStorage::Private& aData) const
|
||||
{
|
||||
return iInternal == iInternal &&
|
||||
iPresent == iPresent &&
|
||||
iDevice == aData.iDevice &&
|
||||
iBooksDir == aData.iBooksDir;
|
||||
}
|
||||
|
||||
bool BooksStorage::Private::isMountPoint(QString aPath)
|
||||
{
|
||||
std::string path = aPath.toStdString();
|
||||
std::string parent = path + "/..";
|
||||
struct stat stPath, stParent;
|
||||
return stat(path.c_str(), &stPath) == 0 &&
|
||||
stat(parent.c_str(), &stParent) == 0 &&
|
||||
stPath.st_dev != stParent.st_dev;
|
||||
}
|
||||
|
||||
QString BooksStorage::Private::mountPoint(QString aPath)
|
||||
{
|
||||
QFileInfo info(aPath);
|
||||
QDir dir = info.isDir() ? QDir(aPath) : info.dir();
|
||||
dir.makeAbsolute();
|
||||
while (!isMountPoint(dir.path()) && !dir.isRoot()) {
|
||||
info.setFile(dir.path());
|
||||
dir = info.dir();
|
||||
}
|
||||
return dir.path();
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksStorage
|
||||
// ==========================================================================
|
||||
|
||||
BooksStorage::BooksStorage() :
|
||||
QObject(NULL),
|
||||
iPrivate(NULL),
|
||||
iPassThrough(false)
|
||||
{
|
||||
}
|
||||
|
||||
BooksStorage::BooksStorage(const BooksStorage& aStorage) :
|
||||
QObject(NULL),
|
||||
iPrivate(aStorage.iPrivate),
|
||||
iPassThrough(false)
|
||||
{
|
||||
if (iPrivate) iPrivate->iRef.ref();
|
||||
}
|
||||
|
||||
BooksStorage::BooksStorage(QString aDevice, QDir aBooksDir, bool aInternal) :
|
||||
QObject(NULL),
|
||||
iPrivate(new Private(aDevice, aBooksDir, aInternal)),
|
||||
iPassThrough(false)
|
||||
{
|
||||
HDEBUG("config dir" << qPrintable(configDir().path()));
|
||||
}
|
||||
|
||||
BooksStorage::~BooksStorage()
|
||||
{
|
||||
if (iPrivate && !iPrivate->iRef.deref()) delete iPrivate;
|
||||
}
|
||||
|
||||
void BooksStorage::connectNotify(const QMetaMethod& aSignal)
|
||||
{
|
||||
if (iPrivate && !iPassThrough) {
|
||||
iPassThrough = true;
|
||||
connect(iPrivate, SIGNAL(removed()), SIGNAL(removed()));
|
||||
}
|
||||
|
||||
// Prototype of this method has changed in Qt5. Make sure that
|
||||
// compilation breaks on Qt with older version of Qt:
|
||||
QObject::connectNotify(aSignal);
|
||||
}
|
||||
|
||||
QString BooksStorage::device() const
|
||||
{
|
||||
return iPrivate ? iPrivate->iDevice : QString();
|
||||
}
|
||||
|
||||
QDir BooksStorage::booksDir() const
|
||||
{
|
||||
return iPrivate ? iPrivate->iBooksDir : QDir();
|
||||
}
|
||||
|
||||
QDir BooksStorage::configDir() const
|
||||
{
|
||||
return iPrivate ? iPrivate->iConfigDir : QDir();
|
||||
}
|
||||
|
||||
bool BooksStorage::isInternal() const
|
||||
{
|
||||
return iPrivate && iPrivate->iInternal;
|
||||
}
|
||||
|
||||
bool BooksStorage::isPresent() const
|
||||
{
|
||||
return iPrivate && iPrivate->iPresent;
|
||||
}
|
||||
|
||||
bool BooksStorage::equal(const BooksStorage& aStorage) const
|
||||
{
|
||||
if (iPrivate == aStorage.iPrivate) {
|
||||
return true;
|
||||
} else if (!iPrivate || !aStorage.iPrivate) {
|
||||
return false;
|
||||
} else {
|
||||
return iPrivate->equal(*aStorage.iPrivate);
|
||||
}
|
||||
}
|
||||
|
||||
BooksStorage& BooksStorage::operator = (const BooksStorage& aStorage)
|
||||
{
|
||||
if (iPrivate != aStorage.iPrivate) {
|
||||
if (iPrivate && !iPrivate->iRef.deref()) delete iPrivate;
|
||||
iPrivate = aStorage.iPrivate;
|
||||
if (iPrivate) iPrivate->iRef.ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// ==========================================================================
|
||||
// BooksStorageManager::Private
|
||||
// ==========================================================================
|
||||
|
||||
#define STORAGE_MOUNTS_FILE "/proc/mounts"
|
||||
|
||||
#define STORAGE_SUBSYSTEM "block"
|
||||
#define STORAGE_DISK "disk"
|
||||
#define STORAGE_PARTITION "partition"
|
||||
#define STORAGE_MOUNT_PREFIX "/media/"
|
||||
|
||||
#define STORAGE_ACTION_ADD "add"
|
||||
#define STORAGE_ACTION_REMOVE "remove"
|
||||
|
||||
#define STORAGE_SCAN_INTERVAL 100
|
||||
#define STORAGE_SCAN_TIMEOUT 5000
|
||||
|
||||
class BooksStorageManager::Private {
|
||||
public:
|
||||
static BooksStorageManager* gInstance;
|
||||
|
||||
Private();
|
||||
~Private();
|
||||
|
||||
int findDevice(QString aDevice) const;
|
||||
int findPath(QString aPath) const;
|
||||
|
||||
public:
|
||||
QList<BooksStorage> iStorageList;
|
||||
struct udev* iUdev;
|
||||
struct udev_monitor* iMonitor;
|
||||
int iDescriptor;
|
||||
QSocketNotifier* iNotifier;
|
||||
QTimer* iScanMountsTimer;
|
||||
QDateTime iScanDeadline;
|
||||
};
|
||||
|
||||
BooksStorageManager* BooksStorageManager::Private::gInstance = NULL;
|
||||
|
||||
BooksStorageManager::Private::Private() :
|
||||
iUdev(udev_new()),
|
||||
iMonitor(NULL),
|
||||
iDescriptor(-1),
|
||||
iNotifier(NULL),
|
||||
iScanMountsTimer(NULL)
|
||||
{
|
||||
QString homeDevice;
|
||||
QString homeBooks = QDir::homePath();
|
||||
QString homeMount(BooksStorage::Private::mountPoint(homeBooks));
|
||||
if (!homeBooks.endsWith('/')) homeBooks += '/';
|
||||
homeBooks += QLatin1String(BOOKS_ROOT_SHELF_DIR);
|
||||
HDEBUG("home mount" << qPrintable(homeMount));
|
||||
HDEBUG("home books path" << qPrintable(homeBooks));
|
||||
|
||||
QFile mounts(STORAGE_MOUNTS_FILE);
|
||||
if (mounts.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
// For some reason QTextStream can't read /proc/mounts line by line
|
||||
QByteArray contents = mounts.readAll();
|
||||
QTextStream in(&contents);
|
||||
QString mediaPrefix(STORAGE_MOUNT_PREFIX);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
QStringList entries = line.split(' ', QString::SkipEmptyParts);
|
||||
if (entries.count() > 2) {
|
||||
QString mount(entries.at(1));
|
||||
if (mount == homeMount) {
|
||||
homeDevice = entries.at(0);
|
||||
HDEBUG("home device" << homeDevice);
|
||||
} else if (mount.startsWith(mediaPrefix)) {
|
||||
QString dev = entries.at(0);
|
||||
QString path = mount;
|
||||
if (!path.endsWith('/')) path += '/';
|
||||
path += QLatin1String(BOOKS_ROOT_SHELF_DIR);
|
||||
HDEBUG("removable device" << dev << path);
|
||||
iStorageList.append(BooksStorage(dev, path, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
mounts.close();
|
||||
}
|
||||
|
||||
iStorageList.insert(0, BooksStorage(homeDevice, homeBooks, true));
|
||||
|
||||
if (iUdev) {
|
||||
iMonitor = udev_monitor_new_from_netlink(iUdev, "udev");
|
||||
if (iMonitor) {
|
||||
udev_monitor_filter_add_match_subsystem_devtype(iMonitor,
|
||||
STORAGE_SUBSYSTEM, NULL);
|
||||
udev_monitor_enable_receiving(iMonitor);
|
||||
iDescriptor = udev_monitor_get_fd(iMonitor);
|
||||
if (iDescriptor >= 0) {
|
||||
iNotifier = new QSocketNotifier(iDescriptor,
|
||||
QSocketNotifier::Read);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BooksStorageManager::Private::findDevice(QString aDevice) const
|
||||
{
|
||||
const int n = iStorageList.count();
|
||||
for (int i=0; i<n; i++) {
|
||||
BooksStorage::Private* data = iStorageList.at(i).iPrivate;
|
||||
if (data->iDevice == aDevice) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int BooksStorageManager::Private::findPath(QString aPath) const
|
||||
{
|
||||
if (!aPath.isEmpty()) {
|
||||
const int n = iStorageList.count();
|
||||
for (int i=0; i<n; i++) {
|
||||
BooksStorage::Private* data = iStorageList.at(i).iPrivate;
|
||||
if (aPath.startsWith(data->iBooksDir.path())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
BooksStorageManager::Private::~Private()
|
||||
{
|
||||
if (iUdev) {
|
||||
if (iMonitor) {
|
||||
if (iDescriptor >= 0) {
|
||||
delete iNotifier;
|
||||
close(iDescriptor);
|
||||
}
|
||||
udev_monitor_unref(iMonitor);
|
||||
}
|
||||
udev_unref(iUdev);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksStorageManager
|
||||
// ==========================================================================
|
||||
|
||||
BooksStorageManager* BooksStorageManager::instance()
|
||||
{
|
||||
if (!Private::gInstance) {
|
||||
Private::gInstance = new BooksStorageManager;
|
||||
}
|
||||
return Private::gInstance;
|
||||
}
|
||||
|
||||
void BooksStorageManager::deleteInstance()
|
||||
{
|
||||
delete Private::gInstance;
|
||||
HASSERT(!Private::gInstance);
|
||||
}
|
||||
|
||||
BooksStorageManager::BooksStorageManager() :
|
||||
iPrivate(new Private)
|
||||
{
|
||||
if (iPrivate->iNotifier) {
|
||||
connect(iPrivate->iNotifier, SIGNAL(activated(int)),
|
||||
SLOT(onDeviceEvent(int)));
|
||||
}
|
||||
}
|
||||
|
||||
BooksStorageManager::~BooksStorageManager()
|
||||
{
|
||||
if (Private::gInstance == this) {
|
||||
Private::gInstance = NULL;
|
||||
}
|
||||
delete iPrivate;
|
||||
}
|
||||
|
||||
int BooksStorageManager::count() const
|
||||
{
|
||||
return iPrivate->iStorageList.count();
|
||||
}
|
||||
|
||||
QList<BooksStorage> BooksStorageManager::storageList() const
|
||||
{
|
||||
return iPrivate->iStorageList;
|
||||
}
|
||||
|
||||
BooksStorage BooksStorageManager::storageForDevice(QString aDevice) const
|
||||
{
|
||||
int index = iPrivate->findDevice(aDevice);
|
||||
return (index >= 0) ? iPrivate->iStorageList.at(index) : BooksStorage();
|
||||
}
|
||||
|
||||
BooksStorage BooksStorageManager::storageForPath(QString aPath) const
|
||||
{
|
||||
int index = iPrivate->findPath(aPath);
|
||||
return (index >= 0) ? iPrivate->iStorageList.at(index) : BooksStorage();
|
||||
}
|
||||
|
||||
void BooksStorageManager::onDeviceEvent(int)
|
||||
{
|
||||
struct udev_device* dev = udev_monitor_receive_device(iPrivate->iMonitor);
|
||||
if (dev) {
|
||||
const char* devnode = udev_device_get_devnode(dev);
|
||||
const char* action = udev_device_get_action(dev);
|
||||
HDEBUG("got device");
|
||||
HDEBUG(" node:" << devnode);
|
||||
HDEBUG(" subsystem:" << udev_device_get_subsystem(dev));
|
||||
HDEBUG(" devtype:" << udev_device_get_devtype(dev));
|
||||
HDEBUG(" action:" << action);
|
||||
if (devnode && action) {
|
||||
if (!(strcmp(action, STORAGE_ACTION_ADD))) {
|
||||
// Mount list isn't updated yet when we receive this
|
||||
// notification. It takes hundreds of milliseconds until
|
||||
// it gets mounted and becomes accessible.
|
||||
if (!scanMounts()) {
|
||||
HDEBUG("no new mounts found");
|
||||
if (!iPrivate->iScanMountsTimer) {
|
||||
QTimer* timer = new QTimer(this);
|
||||
timer->setSingleShot(false);
|
||||
timer->setInterval(STORAGE_SCAN_INTERVAL);
|
||||
connect(timer, SIGNAL(timeout()), SLOT(onScanMounts()));
|
||||
iPrivate->iScanMountsTimer = timer;
|
||||
}
|
||||
iPrivate->iScanMountsTimer->start();
|
||||
iPrivate->iScanDeadline = QDateTime::currentDateTime().
|
||||
addMSecs(STORAGE_SCAN_TIMEOUT);
|
||||
}
|
||||
} else if (!(strcmp(action, STORAGE_ACTION_REMOVE))) {
|
||||
int pos = iPrivate->findDevice(devnode);
|
||||
if (pos >= 0) {
|
||||
HDEBUG("removable device is gone");
|
||||
BooksStorage storage = iPrivate->iStorageList.takeAt(pos);
|
||||
storage.iPrivate->iPresent = false;
|
||||
Q_EMIT storage.iPrivate->removed();
|
||||
Q_EMIT storageRemoved(storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
} else {
|
||||
HWARN("no device!");
|
||||
}
|
||||
}
|
||||
|
||||
bool BooksStorageManager::scanMounts()
|
||||
{
|
||||
bool newStorageFound = false;
|
||||
QFile mounts(STORAGE_MOUNTS_FILE);
|
||||
if (mounts.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
// For some reason QTextStream can't read /proc/mounts line by line
|
||||
QByteArray contents = mounts.readAll();
|
||||
QTextStream in(&contents);
|
||||
QString mediaPrefix(STORAGE_MOUNT_PREFIX);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
QStringList entries = line.split(' ', QString::SkipEmptyParts);
|
||||
if (entries.count() > 2) {
|
||||
QString mount(entries.at(1));
|
||||
if (mount.startsWith(mediaPrefix)) {
|
||||
QString dev = entries.at(0);
|
||||
int index = iPrivate->findDevice(dev);
|
||||
if (index < 0) {
|
||||
QString path = mount;
|
||||
if (!path.endsWith('/')) path += '/';
|
||||
path += QLatin1String(BOOKS_ROOT_SHELF_DIR);
|
||||
HDEBUG("new removable device" << dev << path);
|
||||
BooksStorage storage(dev, path, false);
|
||||
iPrivate->iStorageList.append(storage);
|
||||
Q_EMIT storageAdded(storage);
|
||||
newStorageFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mounts.close();
|
||||
}
|
||||
return newStorageFound;
|
||||
}
|
||||
|
||||
void BooksStorageManager::onScanMounts()
|
||||
{
|
||||
if (scanMounts()) {
|
||||
iPrivate->iScanMountsTimer->stop();
|
||||
} else {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
if (now > iPrivate->iScanDeadline) {
|
||||
HDEBUG("timeout waiting for new mount to appear");
|
||||
iPrivate->iScanMountsTimer->stop();
|
||||
} else {
|
||||
HDEBUG("no new mounts found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "BooksStorage.moc"
|
115
app/src/BooksStorage.h
Normal file
115
app/src/BooksStorage.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_STORAGE_H
|
||||
#define BOOKS_STORAGE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QDir>
|
||||
|
||||
class BooksStorageManager;
|
||||
|
||||
class BooksStorage: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString root READ root CONSTANT)
|
||||
|
||||
public:
|
||||
BooksStorage();
|
||||
BooksStorage(const BooksStorage& aStorage);
|
||||
~BooksStorage();
|
||||
|
||||
QString device() const;
|
||||
QDir booksDir() const;
|
||||
QDir configDir() const;
|
||||
QString label() const { return booksDir().dirName(); }
|
||||
QString root() const { return booksDir().path(); }
|
||||
|
||||
bool isValid() const { return iPrivate != NULL; }
|
||||
bool isInternal() const;
|
||||
bool isPresent() const;
|
||||
bool equal(const BooksStorage& aStorage) const;
|
||||
|
||||
BooksStorage& operator = (const BooksStorage& aStorage);
|
||||
bool operator == (const BooksStorage& aStorage) const
|
||||
{ return equal(aStorage); }
|
||||
|
||||
Q_SIGNALS:
|
||||
void removed();
|
||||
|
||||
private:
|
||||
friend class BooksStorageManager;
|
||||
BooksStorage(QString, QDir, bool);
|
||||
void connectNotify(const QMetaMethod& aSignal);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* iPrivate;
|
||||
bool iPassThrough;
|
||||
};
|
||||
|
||||
class BooksStorageManager: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static BooksStorageManager* instance();
|
||||
static void deleteInstance();
|
||||
~BooksStorageManager();
|
||||
|
||||
int count() const;
|
||||
QList<BooksStorage> storageList() const;
|
||||
BooksStorage storageForDevice(QString aDevice) const;
|
||||
BooksStorage storageForPath(QString aPath) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void storageAdded(BooksStorage aStorage);
|
||||
void storageRemoved(BooksStorage aStorage);
|
||||
|
||||
private:
|
||||
BooksStorageManager();
|
||||
bool scanMounts();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onDeviceEvent(int);
|
||||
void onScanMounts();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* iPrivate;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(BooksStorage)
|
||||
|
||||
#endif // BOOKS_STORAGE_H
|
198
app/src/BooksStorageModel.cpp
Normal file
198
app/src/BooksStorageModel.cpp
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksStorageModel.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
enum BooksStorageRole {
|
||||
BooksStorageRoot = Qt::UserRole,
|
||||
BooksStorageDevice,
|
||||
BooksStorageRemovable,
|
||||
BooksStorageDeleteAllRequest
|
||||
};
|
||||
|
||||
// ==========================================================================
|
||||
// BooksStorageModel::Data
|
||||
// ==========================================================================
|
||||
|
||||
class BooksStorageModel::Data {
|
||||
public:
|
||||
Data(const BooksStorage& aStorage);
|
||||
|
||||
QString device() const { return iStorage.device(); }
|
||||
QString root() const { return iStorage.root(); }
|
||||
bool isRemovable() const { return !iStorage.isInternal(); }
|
||||
|
||||
public:
|
||||
BooksStorage iStorage;
|
||||
bool iDeleteAllRequest;
|
||||
};
|
||||
|
||||
BooksStorageModel::Data::Data(const BooksStorage& aStorage) :
|
||||
iStorage(aStorage),
|
||||
iDeleteAllRequest(false)
|
||||
{
|
||||
// Pointers to these objects can be returned to QML
|
||||
QQmlEngine::setObjectOwnership(&iStorage, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// BooksStorageModel
|
||||
// ==========================================================================
|
||||
|
||||
BooksStorageModel::BooksStorageModel(QObject* aParent) :
|
||||
QAbstractListModel(aParent)
|
||||
{
|
||||
#if QT_VERSION < 0x050000
|
||||
setRoleNames(roleNames());
|
||||
#endif
|
||||
|
||||
BooksStorageManager* mgr = BooksStorageManager::instance();
|
||||
QList<BooksStorage> list = mgr->storageList();
|
||||
const int n = list.count();
|
||||
for (int i=0; i<n; i++) iList.append(new Data(list.at(i)));
|
||||
iInternalStorage = list.at(0);
|
||||
QQmlEngine::setObjectOwnership(&iInternalStorage, QQmlEngine::CppOwnership);
|
||||
connect(mgr,
|
||||
SIGNAL(storageAdded(BooksStorage)),
|
||||
SLOT(onStorageAdded(BooksStorage)));
|
||||
connect(mgr,
|
||||
SIGNAL(storageRemoved(BooksStorage)),
|
||||
SLOT(onStorageRemoved(BooksStorage)));
|
||||
}
|
||||
|
||||
BooksStorageModel::~BooksStorageModel()
|
||||
{
|
||||
HDEBUG("destroyed");
|
||||
}
|
||||
|
||||
int BooksStorageModel::count() const
|
||||
{
|
||||
return iList.count();
|
||||
}
|
||||
|
||||
void BooksStorageModel::setDeleteAllRequest(int aIndex, bool aValue)
|
||||
{
|
||||
if (validIndex(aIndex)) {
|
||||
Data* data = iList.at(aIndex);
|
||||
if (data->iDeleteAllRequest != aValue) {
|
||||
data->iDeleteAllRequest = aValue;
|
||||
QModelIndex index(createIndex(aIndex, 0));
|
||||
QVector<int> roles;
|
||||
roles.append(BooksStorageDeleteAllRequest);
|
||||
HDEBUG(aValue << data->root());
|
||||
Q_EMIT dataChanged(index, index, roles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BooksStorageModel::cancelDeleteAllRequests()
|
||||
{
|
||||
for (int i=iList.count()-1; i>=0; i--) {
|
||||
setDeleteAllRequest(i, false);
|
||||
}
|
||||
}
|
||||
|
||||
QObject* BooksStorageModel::get(int aIndex) const
|
||||
{
|
||||
if (validIndex(aIndex)) {
|
||||
return &(iList.at(aIndex)->iStorage);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QHash<int,QByteArray> BooksStorageModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles.insert(BooksStorageRemovable, "removable");
|
||||
roles.insert(BooksStorageRoot, "root");
|
||||
roles.insert(BooksStorageDevice, "device");
|
||||
roles.insert(BooksStorageDeleteAllRequest, "deleteAllRequest");
|
||||
return roles;
|
||||
}
|
||||
|
||||
int BooksStorageModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return iList.count();
|
||||
}
|
||||
|
||||
QVariant BooksStorageModel::data(const QModelIndex& aIndex, int aRole) const
|
||||
{
|
||||
const int i = aIndex.row();
|
||||
if (validIndex(i)) {
|
||||
Data* data = iList.at(i);
|
||||
switch (aRole) {
|
||||
case BooksStorageRoot: return data->root();
|
||||
case BooksStorageDevice: return data->device();
|
||||
case BooksStorageRemovable: return data->isRemovable();
|
||||
case BooksStorageDeleteAllRequest: return data->iDeleteAllRequest;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int BooksStorageModel::find(const BooksStorage& aStorage) const
|
||||
{
|
||||
const int n = iList.count();
|
||||
for (int i=0; i<n; i++) {
|
||||
if (iList.at(i)->iStorage.equal(aStorage)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void BooksStorageModel::onStorageAdded(BooksStorage aStorage)
|
||||
{
|
||||
HDEBUG(aStorage.device() << "found");
|
||||
const int index = iList.count();
|
||||
beginInsertRows(QModelIndex(), index, index);
|
||||
iList.append(new Data(aStorage));
|
||||
endInsertRows();
|
||||
Q_EMIT countChanged();
|
||||
Q_EMIT newStorage(index);
|
||||
}
|
||||
|
||||
void BooksStorageModel::onStorageRemoved(BooksStorage aStorage)
|
||||
{
|
||||
int index = find(aStorage);
|
||||
if (index >=0) {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
delete iList.takeAt(index);
|
||||
endRemoveRows();
|
||||
Q_EMIT countChanged();
|
||||
} else {
|
||||
HWARN("device not dfound on the list");
|
||||
}
|
||||
}
|
89
app/src/BooksStorageModel.h
Normal file
89
app/src/BooksStorageModel.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_STORAGE_MODEL_H
|
||||
#define BOOKS_STORAGE_MODEL_H
|
||||
|
||||
#include "BooksStorage.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
#include <QAbstractListModel>
|
||||
#include <QtQml>
|
||||
|
||||
class BooksStorageModel: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||
Q_PROPERTY(QObject* internalStorage READ internalStorage CONSTANT)
|
||||
|
||||
public:
|
||||
explicit BooksStorageModel(QObject* aParent = NULL);
|
||||
~BooksStorageModel();
|
||||
|
||||
Q_INVOKABLE int count() const;
|
||||
Q_INVOKABLE void setDeleteAllRequest(int aIndex, bool aValue);
|
||||
Q_INVOKABLE void cancelDeleteAllRequests();
|
||||
Q_INVOKABLE QObject* get(int aIndex) const;
|
||||
QObject* internalStorage() { return &iInternalStorage; }
|
||||
|
||||
// QAbstractListModel
|
||||
virtual QHash<int,QByteArray> roleNames() const;
|
||||
virtual int rowCount(const QModelIndex& aParent) const;
|
||||
virtual QVariant data(const QModelIndex& aIndex, int aRole) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void countChanged();
|
||||
void newStorage(int index);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onStorageAdded(BooksStorage aStorage);
|
||||
void onStorageRemoved(BooksStorage aStorage);
|
||||
|
||||
private:
|
||||
bool validIndex(int aIndex) const;
|
||||
int find(const BooksStorage& aStorage) const;
|
||||
|
||||
private:
|
||||
class Data;
|
||||
QList<Data*> iList;
|
||||
BooksStorage iInternalStorage;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(BooksStorageModel)
|
||||
|
||||
inline bool BooksStorageModel::validIndex(int aIndex) const
|
||||
{ return aIndex >= 0 && aIndex < iList.count(); }
|
||||
|
||||
#endif // BOOKS_STORAGE_MODEL_H
|
90
app/src/BooksTask.cpp
Normal file
90
app/src/BooksTask.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksTask.h"
|
||||
#include "BooksTaskQueue.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
BooksTask::BooksTask() :
|
||||
iAboutToQuit(false),
|
||||
iReleased(false),
|
||||
iStarted(false),
|
||||
iDone(false)
|
||||
{
|
||||
setAutoDelete(false);
|
||||
connect(qApp, SIGNAL(aboutToQuit()), SLOT(onAboutToQuit()));
|
||||
connect(this, SIGNAL(runFinished()), SLOT(onRunFinished()),
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
BooksTask::~BooksTask()
|
||||
{
|
||||
HASSERT(iReleased);
|
||||
if (iStarted) wait();
|
||||
}
|
||||
|
||||
void BooksTask::release(QObject* aHandler)
|
||||
{
|
||||
disconnect(aHandler);
|
||||
iReleased = true;
|
||||
if (!iStarted || iDone) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void BooksTask::run()
|
||||
{
|
||||
performTask();
|
||||
Q_EMIT runFinished();
|
||||
}
|
||||
|
||||
void BooksTask::onRunFinished()
|
||||
{
|
||||
HASSERT(!iDone);
|
||||
if (!iReleased) {
|
||||
Q_EMIT done();
|
||||
}
|
||||
iDone = true;
|
||||
if (iReleased) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void BooksTask::onAboutToQuit()
|
||||
{
|
||||
HDEBUG("OK");
|
||||
iAboutToQuit = true;
|
||||
}
|
76
app/src/BooksTask.h
Normal file
76
app/src/BooksTask.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_TASK_H
|
||||
#define BOOKS_TASK_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QRunnable>
|
||||
|
||||
class BooksTaskQueue;
|
||||
|
||||
class BooksTask : public QObject, public QRunnable
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class BooksTaskQueue;
|
||||
|
||||
protected:
|
||||
BooksTask();
|
||||
|
||||
public:
|
||||
virtual ~BooksTask();
|
||||
|
||||
void release(QObject* aHandler);
|
||||
|
||||
protected:
|
||||
bool isCanceled() const { return iReleased || iAboutToQuit; }
|
||||
|
||||
virtual void run();
|
||||
virtual void performTask() = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
void runFinished();
|
||||
void done();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onAboutToQuit();
|
||||
void onRunFinished();
|
||||
|
||||
private:
|
||||
bool iAboutToQuit;
|
||||
bool iReleased;
|
||||
bool iStarted;
|
||||
bool iDone;
|
||||
};
|
||||
|
||||
#endif // BOOKS_TASK_H
|
87
app/src/BooksTaskQueue.cpp
Normal file
87
app/src/BooksTaskQueue.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksTaskQueue.h"
|
||||
#include "BooksTask.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
static weak_ptr<BooksTaskQueue> booksTaskQueueInstance;
|
||||
|
||||
shared_ptr<BooksTaskQueue> BooksTaskQueue::instance()
|
||||
{
|
||||
shared_ptr<BooksTaskQueue> worker;
|
||||
if (booksTaskQueueInstance.isNull()) {
|
||||
booksTaskQueueInstance = (worker = new BooksTaskQueue());
|
||||
} else {
|
||||
worker = booksTaskQueueInstance;
|
||||
}
|
||||
return worker;
|
||||
}
|
||||
|
||||
BooksTaskQueue::BooksTaskQueue() :
|
||||
iPool(new QThreadPool)
|
||||
{
|
||||
HDEBUG("created");
|
||||
iPool->setMaxThreadCount(1);
|
||||
}
|
||||
|
||||
void BooksTaskQueue::waitForDone(int aMsecs)
|
||||
{
|
||||
shared_ptr<BooksTaskQueue> worker = booksTaskQueueInstance;
|
||||
if (!worker.isNull()) {
|
||||
worker->iPool->waitForDone(aMsecs);
|
||||
}
|
||||
}
|
||||
|
||||
BooksTaskQueue::~BooksTaskQueue()
|
||||
{
|
||||
HDEBUG("deleting");
|
||||
iPool->waitForDone();
|
||||
delete iPool;
|
||||
HDEBUG("deleted");
|
||||
}
|
||||
|
||||
void BooksTaskQueue::submit(BooksTask* aTask)
|
||||
{
|
||||
HASSERT(!aTask->iStarted);
|
||||
aTask->iStarted = true;
|
||||
iPool->start(aTask);
|
||||
}
|
||||
|
||||
void BooksTaskQueue::submit(BooksTask* aTask, QObject* aTarget,
|
||||
const char* aSlot)
|
||||
{
|
||||
QObject::connect(aTask, SIGNAL(done()), aTarget, aSlot);
|
||||
submit(aTask);
|
||||
}
|
62
app/src/BooksTaskQueue.h
Normal file
62
app/src/BooksTaskQueue.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_TASK_QUEUE_H
|
||||
#define BOOKS_TASK_QUEUE_H
|
||||
|
||||
#include "shared_ptr.h"
|
||||
|
||||
#include <QThreadPool>
|
||||
|
||||
class BooksTask;
|
||||
|
||||
class BooksTaskQueue
|
||||
{
|
||||
friend class shared_ptr_storage<BooksTaskQueue>;
|
||||
|
||||
public:
|
||||
static shared_ptr<BooksTaskQueue> instance();
|
||||
static void waitForDone(int aMsecs = -1);
|
||||
|
||||
void submit(BooksTask* aTask);
|
||||
void submit(BooksTask* aTask, QObject* aTarget, const char* aSlot);
|
||||
|
||||
private:
|
||||
BooksTaskQueue();
|
||||
~BooksTaskQueue();
|
||||
|
||||
private:
|
||||
QThreadPool* iPool;
|
||||
};
|
||||
|
||||
#endif // BOOKS_TASK_QUEUE_H
|
140
app/src/BooksTextStyle.cpp
Normal file
140
app/src/BooksTextStyle.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksTextStyle.h"
|
||||
#include "BooksDefs.h"
|
||||
|
||||
class BooksTextStyle::Default
|
||||
{
|
||||
public:
|
||||
static weak_ptr<ZLTextStyle> instance;
|
||||
static const std::string FONT_FAMILY;
|
||||
};
|
||||
|
||||
weak_ptr<ZLTextStyle> BooksTextStyle::Default::instance;
|
||||
const std::string BooksTextStyle::Default::FONT_FAMILY("Times");
|
||||
|
||||
shared_ptr<ZLTextStyle> BooksTextStyle::defaults()
|
||||
{
|
||||
shared_ptr<ZLTextStyle> style = Default::instance;
|
||||
if (style.isNull()) {
|
||||
style = new BooksTextStyle;
|
||||
Default::instance = style;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
bool
|
||||
BooksTextStyle::equalLayout(
|
||||
shared_ptr<ZLTextStyle> aStyle1,
|
||||
shared_ptr<ZLTextStyle> aStyle2)
|
||||
{
|
||||
if (aStyle1.isNull()) aStyle1 = defaults();
|
||||
if (aStyle2.isNull()) aStyle2 = defaults();
|
||||
return aStyle1->fontSize() == aStyle2->fontSize();
|
||||
}
|
||||
|
||||
const std::string& BooksTextStyle::colorStyle() const
|
||||
{
|
||||
return REGULAR_TEXT;
|
||||
}
|
||||
|
||||
bool BooksTextStyle::isDecorated() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& BooksTextStyle::fontFamily() const
|
||||
{
|
||||
return Default::FONT_FAMILY;
|
||||
}
|
||||
|
||||
int BooksTextStyle::fontSize() const
|
||||
{
|
||||
return (26 * BOOKS_PPI / 330) & (~1); // Make sure it's divisible by 2
|
||||
}
|
||||
|
||||
bool BooksTextStyle::bold() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BooksTextStyle::italic() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
short BooksTextStyle::spaceBefore(const ZLTextStyleEntry::Metrics&) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
short BooksTextStyle::spaceAfter(const ZLTextStyleEntry::Metrics&) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
short BooksTextStyle::lineStartIndent(const ZLTextStyleEntry::Metrics&, bool) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
short BooksTextStyle::lineEndIndent(const ZLTextStyleEntry::Metrics&, bool) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
short BooksTextStyle::firstLineIndentDelta(const ZLTextStyleEntry::Metrics&) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BooksTextStyle::verticalShift() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZLTextAlignmentType BooksTextStyle::alignment() const
|
||||
{
|
||||
return ALIGN_JUSTIFY;
|
||||
}
|
||||
|
||||
double BooksTextStyle::lineSpace() const
|
||||
{
|
||||
return 1.4;
|
||||
}
|
||||
|
||||
bool BooksTextStyle::allowHyphenations() const
|
||||
{
|
||||
return true;
|
||||
}
|
78
app/src/BooksTextStyle.h
Normal file
78
app/src/BooksTextStyle.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_TEXT_STYLE_H
|
||||
#define BOOKS_TEXT_STYLE_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
|
||||
#include <ZLTextStyle.h>
|
||||
|
||||
class BooksTextStyle : public ZLTextStyle
|
||||
{
|
||||
class Default;
|
||||
public:
|
||||
static shared_ptr<ZLTextStyle> defaults();
|
||||
static bool equalLayout(shared_ptr<ZLTextStyle> aStyle1, shared_ptr<ZLTextStyle> aStyle2);
|
||||
|
||||
private:
|
||||
static weak_ptr<ZLTextStyle> gInstance;
|
||||
|
||||
private:
|
||||
BooksTextStyle() {}
|
||||
|
||||
public:
|
||||
bool isDecorated() const;
|
||||
|
||||
const std::string &fontFamily() const;
|
||||
|
||||
int fontSize() const;
|
||||
bool bold() const;
|
||||
bool italic() const;
|
||||
|
||||
const std::string &colorStyle() const;
|
||||
|
||||
short spaceBefore(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
||||
short spaceAfter(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
||||
short lineStartIndent(const ZLTextStyleEntry::Metrics& aMetrics, bool aRtl) const;
|
||||
short lineEndIndent(const ZLTextStyleEntry::Metrics& aMetrics, bool aRtl) const;
|
||||
short firstLineIndentDelta(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
||||
int verticalShift() const;
|
||||
|
||||
ZLTextAlignmentType alignment() const;
|
||||
|
||||
double lineSpace() const;
|
||||
bool allowHyphenations() const;
|
||||
};
|
||||
|
||||
#endif // BOOKS_TEXT_STYLE_H
|
141
app/src/BooksTextView.cpp
Normal file
141
app/src/BooksTextView.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksTextView.h"
|
||||
#include "BooksTextStyle.h"
|
||||
|
||||
#include "options/FBOptions.h"
|
||||
|
||||
#define SUPER ZLTextView
|
||||
|
||||
BooksTextView::BooksTextView(
|
||||
ZLPaintContext& aContext,
|
||||
shared_ptr<ZLTextStyle> aTextStyle,
|
||||
BooksMargins aMargins) :
|
||||
SUPER(aContext),
|
||||
iMargins(aMargins),
|
||||
iBackgroundColor(255, 255, 255),
|
||||
iTextStyle(aTextStyle)
|
||||
{
|
||||
}
|
||||
|
||||
void BooksTextView::paint()
|
||||
{
|
||||
SUPER::paint();
|
||||
}
|
||||
|
||||
const std::string& BooksTextView::caption() const
|
||||
{
|
||||
return iCaption;
|
||||
}
|
||||
|
||||
int BooksTextView::leftMargin() const
|
||||
{
|
||||
return iMargins.iLeft + iTextStyle->fontSize();
|
||||
}
|
||||
|
||||
int BooksTextView::rightMargin() const
|
||||
{
|
||||
return iMargins.iRight + iTextStyle->fontSize();
|
||||
}
|
||||
|
||||
int BooksTextView::topMargin() const
|
||||
{
|
||||
return iMargins.iTop;
|
||||
}
|
||||
|
||||
int BooksTextView::bottomMargin() const
|
||||
{
|
||||
return iMargins.iBottom;
|
||||
}
|
||||
|
||||
ZLColor BooksTextView::backgroundColor() const
|
||||
{
|
||||
return iBackgroundColor;
|
||||
}
|
||||
|
||||
ZLColor BooksTextView::color(const std::string &colorStyle) const
|
||||
{
|
||||
return FBOptions::Instance().colorOption(colorStyle).value();
|
||||
}
|
||||
|
||||
shared_ptr<ZLTextStyle> BooksTextView::baseStyle() const
|
||||
{
|
||||
return iTextStyle;
|
||||
}
|
||||
|
||||
bool BooksTextView::isSelectionEnabled() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int BooksTextView::doubleClickDelay() const
|
||||
{
|
||||
return isSelectionEnabled() ? 200 : 0;
|
||||
}
|
||||
|
||||
shared_ptr<ZLTextPositionIndicatorInfo> BooksTextView::indicatorInfo() const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const BooksPos BooksTextView::rewind()
|
||||
{
|
||||
SUPER::gotoPosition(0, 0, 0);
|
||||
preparePaintInfo();
|
||||
if (!textArea().isVisible()) nextPage();
|
||||
return position();
|
||||
}
|
||||
|
||||
bool BooksTextView::nextPage()
|
||||
{
|
||||
BooksPos saved(position());
|
||||
BooksPos current(saved);
|
||||
do {
|
||||
scrollPage(true, ZLTextAreaController::NO_OVERLAPPING, 1);
|
||||
preparePaintInfo();
|
||||
const BooksPos pos = position();
|
||||
if (pos == current) {
|
||||
gotoPosition(saved);
|
||||
return false;
|
||||
}
|
||||
current = pos;
|
||||
} while (!textArea().isVisible());
|
||||
return true;
|
||||
}
|
||||
|
||||
void BooksTextView::gotoPosition(const BooksPos& aPos)
|
||||
{
|
||||
SUPER::gotoPosition(aPos.iParagraphIndex, aPos.iElementIndex,
|
||||
aPos.iCharIndex);
|
||||
}
|
89
app/src/BooksTextView.h
Normal file
89
app/src/BooksTextView.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
Copyright (C) 2015 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 Nemo Mobile 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_TEXT_VIEW_H
|
||||
#define BOOKS_TEXT_VIEW_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
#include "BooksPos.h"
|
||||
|
||||
#include "ZLColor.h"
|
||||
#include "ZLTextView.h"
|
||||
#include "ZLTextModel.h"
|
||||
#include "ZLTextStyle.h"
|
||||
#include "ZLPaintContext.h"
|
||||
|
||||
class BooksTextView: public ZLTextView
|
||||
{
|
||||
public:
|
||||
BooksTextView(ZLPaintContext& aContext,
|
||||
shared_ptr<ZLTextStyle> aTextStyle,
|
||||
BooksMargins aMargin);
|
||||
|
||||
public:
|
||||
BooksPos position() const;
|
||||
const BooksPos rewind();
|
||||
void gotoPosition(const BooksPos& aPos);
|
||||
bool nextPage();
|
||||
void paint();
|
||||
|
||||
// ZLView
|
||||
virtual const std::string &caption() const;
|
||||
virtual ZLColor backgroundColor() const;
|
||||
|
||||
// ZLTextView
|
||||
virtual shared_ptr<ZLTextPositionIndicatorInfo> indicatorInfo() const;
|
||||
virtual int doubleClickDelay() const;
|
||||
virtual int leftMargin() const;
|
||||
virtual int rightMargin() const;
|
||||
virtual int topMargin() const;
|
||||
virtual int bottomMargin() const;
|
||||
|
||||
// ZLTextArea::Properties
|
||||
virtual shared_ptr<ZLTextStyle> baseStyle() const;
|
||||
virtual ZLColor color(const std::string &style = std::string()) const;
|
||||
virtual bool isSelectionEnabled() const;
|
||||
|
||||
public:
|
||||
BooksMargins iMargins;
|
||||
ZLColor iBackgroundColor;
|
||||
|
||||
private:
|
||||
std::string iCaption;
|
||||
shared_ptr<ZLTextStyle> iTextStyle;
|
||||
};
|
||||
|
||||
inline BooksPos BooksTextView::position() const
|
||||
{ return BooksPos(textArea().startCursor()); }
|
||||
|
||||
#endif // BOOKS_TEXT_VIEW_H
|
50
app/src/BooksTypes.h
Normal file
50
app/src/BooksTypes.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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_TYPES_H
|
||||
#define BOOKS_TYPES_H
|
||||
|
||||
#include "shared_ptr.h"
|
||||
|
||||
class BooksBook;
|
||||
class BooksShelf;
|
||||
|
||||
struct BooksMargins {
|
||||
int iLeft;
|
||||
int iRight;
|
||||
int iTop;
|
||||
int iBottom;
|
||||
BooksMargins() : iLeft(0), iRight(0), iTop(0), iBottom(0) {}
|
||||
};
|
||||
|
||||
#endif // BOOKS_TYPES_H
|
150
app/src/ZLApplication.cpp
Normal file
150
app/src/ZLApplication.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksDefs.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include "ZLApplication.h"
|
||||
#include "ZLApplicationWindow.h"
|
||||
#include "ZLPaintContext.h"
|
||||
#include "ZLViewWidget.h"
|
||||
#include "ZLKeyBindings.h"
|
||||
#include "ZLPopupData.h"
|
||||
#include "ZLToolbar.h"
|
||||
#include "ZLMenu.h"
|
||||
|
||||
// We are not currently using ZLApplication and ZLApplicationWindow but
|
||||
// there are some references to it from the fbreader code which we must
|
||||
// resolve.
|
||||
|
||||
ZLApplication *ZLApplication::ourInstance = NULL;
|
||||
|
||||
static const std::string ROTATION = "Rotation";
|
||||
static const std::string ANGLE = "Angle";
|
||||
static const std::string STATE = "State";
|
||||
static const std::string KEYBOARD = "Keyboard";
|
||||
static const std::string FULL_CONTROL = "FullControl";
|
||||
static const std::string CONFIG = "Config";
|
||||
static const std::string AUTO_SAVE = "AutoSave";
|
||||
static const std::string TIMEOUT = "Timeout";
|
||||
|
||||
ZLApplication &ZLApplication::Instance()
|
||||
{
|
||||
if (!ourInstance) new ZLApplication(BOOKS_APP_NAME);
|
||||
return *ourInstance;
|
||||
}
|
||||
|
||||
void ZLApplication::deleteInstance()
|
||||
{
|
||||
if (ourInstance) {
|
||||
delete ourInstance;
|
||||
ourInstance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ZLApplication::ZLApplication(const std::string &name) :
|
||||
ZLApplicationBase(name),
|
||||
RotationAngleOption(ZLCategoryKey::CONFIG, ROTATION, ANGLE, ZLView::DEGREES90),
|
||||
AngleStateOption(ZLCategoryKey::CONFIG, STATE, ANGLE, ZLView::DEGREES0),
|
||||
KeyboardControlOption(ZLCategoryKey::CONFIG, KEYBOARD, FULL_CONTROL, false),
|
||||
ConfigAutoSavingOption(ZLCategoryKey::CONFIG, CONFIG, AUTO_SAVE, true),
|
||||
ConfigAutoSaveTimeoutOption(ZLCategoryKey::CONFIG, CONFIG, TIMEOUT, 1, 6000, 30),
|
||||
KeyDelayOption(ZLCategoryKey::CONFIG, "Options", "KeyDelay", 0, 5000, 250)
|
||||
{
|
||||
ourInstance = this;
|
||||
}
|
||||
|
||||
ZLApplication::~ZLApplication()
|
||||
{
|
||||
}
|
||||
|
||||
void ZLApplication::initWindow()
|
||||
{
|
||||
}
|
||||
|
||||
shared_ptr<ZLKeyBindings> ZLApplication::keyBindings()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ZLApplication::closeView()
|
||||
{
|
||||
HDEBUG("NO");
|
||||
return false;
|
||||
}
|
||||
|
||||
void ZLApplication::openFile(ZLFile const&)
|
||||
{
|
||||
}
|
||||
|
||||
bool ZLApplication::canDragFiles(std::vector<std::string, std::allocator<std::string> > const&) const
|
||||
{
|
||||
HDEBUG("NO");
|
||||
return false;
|
||||
}
|
||||
|
||||
void ZLApplication::dragFiles(std::vector<std::string, std::allocator<std::string> > const&)
|
||||
{
|
||||
HDEBUG("WHAT?");
|
||||
}
|
||||
|
||||
bool ZLApplication::isViewFinal() const
|
||||
{
|
||||
HDEBUG("YES");
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZLApplication::refreshWindow()
|
||||
{
|
||||
HDEBUG("OK");
|
||||
}
|
||||
|
||||
void ZLApplication::setHyperlinkCursor(bool aHyperLink)
|
||||
{
|
||||
HDEBUG(aHyperLink);
|
||||
}
|
||||
|
||||
ZLApplicationWindow &ZLApplicationWindow::Instance()
|
||||
{
|
||||
HDEBUG("THIS IS NOT SUPPOSED TO HAPPEN!");
|
||||
return *((ZLApplicationWindow*)NULL);
|
||||
}
|
||||
|
||||
void ZLApplicationWindow::init()
|
||||
{
|
||||
}
|
||||
|
||||
void ZLApplicationWindow::refresh()
|
||||
{
|
||||
}
|
217
app/src/ZLibrary.cpp
Normal file
217
app/src/ZLibrary.cpp
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksDefs.h"
|
||||
#include "BooksStorage.h"
|
||||
#include "BooksPaintContext.h"
|
||||
#include "BooksDialogManager.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
#include "ZLibrary.h"
|
||||
#include "ZLApplication.h"
|
||||
#include "ZLLanguageUtil.h"
|
||||
|
||||
#include "filesystem/ZLQtFSManager.h"
|
||||
#include "time/ZLQtTime.h"
|
||||
#include "image/ZLQtImageManager.h"
|
||||
#include "iconv/IConvEncodingConverter.h"
|
||||
|
||||
#include <sailfishapp.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QStandardPaths>
|
||||
#include <QQuickView>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
bool ZLibrary::ourLocaleIsInitialized = false;
|
||||
std::string ZLibrary::ourLanguage;
|
||||
std::string ZLibrary::ourCountry;
|
||||
std::string ZLibrary::ourZLibraryDirectory;
|
||||
|
||||
std::string ZLibrary::ourApplicationName;
|
||||
std::string ZLibrary::ourImageDirectory;
|
||||
std::string ZLibrary::ourApplicationImageDirectory;
|
||||
std::string ZLibrary::ourApplicationDirectory;
|
||||
std::string ZLibrary::ourApplicationWritableDirectory;
|
||||
std::string ZLibrary::ourDefaultFilesPathPrefix;
|
||||
|
||||
const std::string ZLibrary::FileNameDelimiter("/");
|
||||
const std::string ZLibrary::PathDelimiter(":");
|
||||
const std::string ZLibrary::EndOfLine("\n");
|
||||
const std::string ZLibrary::BaseDirectory;
|
||||
|
||||
void ZLibrary::initLocale()
|
||||
{
|
||||
const char* locale = setlocale(LC_MESSAGES, "");
|
||||
HDEBUG(locale);
|
||||
if (locale) {
|
||||
std::string sLocale = locale;
|
||||
const int dotIndex = sLocale.find('.');
|
||||
if (dotIndex != -1) sLocale = sLocale.substr(0, dotIndex);
|
||||
const int dashIndex = std::min(sLocale.find('_'), sLocale.find('-'));
|
||||
if (dashIndex == -1) {
|
||||
ourLanguage = sLocale;
|
||||
} else {
|
||||
ourLanguage = sLocale.substr(0, dashIndex);
|
||||
ourCountry = sLocale.substr(dashIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZLPaintContext* ZLibrary::createContext()
|
||||
{
|
||||
HDEBUG("creating context");
|
||||
return new BooksPaintContext();
|
||||
}
|
||||
|
||||
bool ZLibrary::init(int& aArgc, char** &aArgv)
|
||||
{
|
||||
HDEBUG("initializing");
|
||||
|
||||
ZLibrary::parseArguments(aArgc, aArgv);
|
||||
|
||||
std::string rootDir("/");
|
||||
Dl_info info;
|
||||
void* addr = NULL;
|
||||
if (backtrace(&addr, 1) && dladdr(addr, &info)) {
|
||||
// Step two levels up. For an application deployed from QtCreator
|
||||
// it's going to be /opt/sdk/<app-name> directory, for a normally
|
||||
// installed app - the root directory.
|
||||
HDEBUG("app path" << info.dli_fname);
|
||||
char* slash = (char*)strrchr(info.dli_fname, '/');
|
||||
if (slash) {
|
||||
slash[0] = 0;
|
||||
HDEBUG("app dir" << info.dli_fname);
|
||||
ourApplicationDirectory = info.dli_fname;
|
||||
slash = (char*)strrchr(info.dli_fname, '/');
|
||||
if (slash) {
|
||||
slash[0] = 0;
|
||||
slash = (char*)strrchr(info.dli_fname, '/');
|
||||
if (slash) {
|
||||
slash[1] = 0;
|
||||
HDEBUG("root dir" << info.dli_fname);
|
||||
rootDir = info.dli_fname;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
((std::string&)BaseDirectory) = rootDir;
|
||||
ourApplicationName = BOOKS_APP_NAME;
|
||||
ourZLibraryDirectory = BaseDirectory + BOOKS_DATA_DIR;
|
||||
ourApplicationDirectory = BaseDirectory + BOOKS_DATA_ROOT;
|
||||
ourImageDirectory = BaseDirectory + BOOKS_ICONS_DIR;
|
||||
ourDefaultFilesPathPrefix = ourZLibraryDirectory + "/";
|
||||
ourApplicationImageDirectory = ourImageDirectory;
|
||||
ourApplicationWritableDirectory =
|
||||
(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
|
||||
QLatin1String("/" BOOKS_APP_NAME)).toStdString();
|
||||
|
||||
HDEBUG("zlibrary dir" << ourZLibraryDirectory.c_str());
|
||||
HDEBUG("image dir" << ourImageDirectory.c_str());
|
||||
HDEBUG("writable dir" << ourApplicationWritableDirectory.c_str());
|
||||
|
||||
BooksStorageManager::instance();
|
||||
ZLQtTimeManager::createInstance();
|
||||
ZLQtFSManager::createInstance();
|
||||
BooksDialogManager::createInstance();
|
||||
ZLQtImageManager::createInstance();
|
||||
ZLEncodingCollection::Instance().registerProvider(new IConvEncodingConverterProvider());
|
||||
ZLApplication::Instance();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZLibrary::run(ZLApplication* aApp)
|
||||
{
|
||||
if (ZLLanguageUtil::isRTLLanguage(ZLibrary::Language())) {
|
||||
qApp->setLayoutDirection(Qt::RightToLeft);
|
||||
}
|
||||
|
||||
QString qml(QString::fromStdString(BaseDirectory + BOOKS_QML_FILE));
|
||||
HDEBUG("qml file" << qPrintable(qml));
|
||||
|
||||
QQuickView* view = SailfishApp::createView();
|
||||
view->setSource(QUrl::fromLocalFile(qml));
|
||||
view->rootContext()->setContextProperty("PointsPerInch", BOOKS_PPI);
|
||||
|
||||
view->show();
|
||||
HDEBUG("started");
|
||||
qApp->exec();
|
||||
HDEBUG("exiting...");
|
||||
}
|
||||
|
||||
void ZLibrary::parseArguments(int &argc, char **&argv)
|
||||
{
|
||||
}
|
||||
|
||||
void ZLibrary::shutdown()
|
||||
{
|
||||
ZLApplication::deleteInstance();
|
||||
ZLImageManager::deleteInstance();
|
||||
ZLDialogManager::deleteInstance();
|
||||
ZLFSManager::deleteInstance();
|
||||
ZLTimeManager::deleteInstance();
|
||||
BooksStorageManager::deleteInstance();
|
||||
}
|
||||
|
||||
void ZLibrary::initApplication(const std::string& aName)
|
||||
{
|
||||
HDEBUG(aName.c_str());
|
||||
}
|
||||
|
||||
std::string ZLibrary::Language()
|
||||
{
|
||||
if (ourLanguage.empty()) {
|
||||
if (!ourLocaleIsInitialized) {
|
||||
initLocale();
|
||||
ourLocaleIsInitialized = true;
|
||||
}
|
||||
}
|
||||
if (ourLanguage.empty()) {
|
||||
ourLanguage = "en";
|
||||
}
|
||||
return ourLanguage;
|
||||
}
|
||||
|
||||
std::string ZLibrary::Country()
|
||||
{
|
||||
if (ourCountry.empty() && !ourLocaleIsInitialized) {
|
||||
initLocale();
|
||||
ourLocaleIsInitialized = true;
|
||||
}
|
||||
return ourCountry;
|
||||
}
|
122
app/src/libudev.c
Normal file
122
app/src/libudev.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 <libudev.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define LIBUDEV_FUNCTIONS(f) \
|
||||
f(struct udev*, udev_unref,\
|
||||
(struct udev* udev), \
|
||||
(udev)) \
|
||||
f(struct udev_monitor*, udev_monitor_new_from_netlink, \
|
||||
(struct udev* udev, const char* name), \
|
||||
(udev, name)) \
|
||||
f(struct udev_device*, udev_monitor_receive_device, \
|
||||
(struct udev_monitor* mon), \
|
||||
(mon)) \
|
||||
f(int, udev_monitor_filter_add_match_subsystem_devtype, \
|
||||
(struct udev_monitor* mon, const char* sub, const char* dev), \
|
||||
(mon, sub, dev)) \
|
||||
f(int, udev_monitor_enable_receiving, \
|
||||
(struct udev_monitor* mon), \
|
||||
(mon)) \
|
||||
f(int, udev_monitor_get_fd, \
|
||||
(struct udev_monitor* mon), \
|
||||
(mon)) \
|
||||
f(struct udev_monitor*, udev_monitor_unref, \
|
||||
(struct udev_monitor* mon), \
|
||||
(mon)) \
|
||||
f(const char*, udev_device_get_devnode, \
|
||||
(struct udev_device* dev), \
|
||||
(dev)) \
|
||||
f(const char*, udev_device_get_devpath, \
|
||||
(struct udev_device* dev), \
|
||||
(dev)) \
|
||||
f(const char*, udev_device_get_subsystem, \
|
||||
(struct udev_device* dev), \
|
||||
(dev)) \
|
||||
f(const char*, udev_device_get_devtype, \
|
||||
(struct udev_device* dev), \
|
||||
(dev)) \
|
||||
f(const char*, udev_device_get_action, \
|
||||
(struct udev_device* dev), \
|
||||
(dev)) \
|
||||
f(struct udev_device*, udev_device_unref, \
|
||||
(struct udev_device* dev), \
|
||||
(dev))
|
||||
|
||||
static struct {
|
||||
void* handle;
|
||||
union {
|
||||
struct libudev_proc {
|
||||
struct udev* (*udev_new)(void);
|
||||
#define FN_POINTER(ret,name,params,args) ret (* name) params;
|
||||
LIBUDEV_FUNCTIONS(FN_POINTER)
|
||||
} udev;
|
||||
void* entry[1];
|
||||
} fn;
|
||||
} libudev;
|
||||
|
||||
static const char* libudev_names[] = {
|
||||
"udev_new",
|
||||
#define FN_NAME(ret,name,params,args) #name,
|
||||
LIBUDEV_FUNCTIONS(FN_NAME)
|
||||
};
|
||||
|
||||
#define LIBUDEV_NUM_FUNCTIONS (sizeof(libudev_names)/sizeof(libudev_names[0]))
|
||||
#define LIBUDEV_NO_HANDLE ((void*)-1)
|
||||
#define LIBUDEV_SO "/usr/lib/libudev.so.1"
|
||||
|
||||
/* udev_new() is the special function where we load the library */
|
||||
struct udev*
|
||||
udev_new()
|
||||
{
|
||||
if (!libudev.handle) {
|
||||
libudev.handle = dlopen(LIBUDEV_SO, RTLD_LAZY);
|
||||
if (libudev.handle) {
|
||||
unsigned int i;
|
||||
for (i=0; i<LIBUDEV_NUM_FUNCTIONS; i++) {
|
||||
libudev.fn.entry[i] = dlsym(libudev.handle, libudev_names[i]);
|
||||
}
|
||||
} else {
|
||||
libudev.handle = LIBUDEV_NO_HANDLE;
|
||||
}
|
||||
}
|
||||
return libudev.fn.udev.udev_new ? libudev.fn.udev.udev_new() : NULL;
|
||||
}
|
||||
|
||||
/* All other wrappers are generated by the preprocessor */
|
||||
#define FN_IMPL(ret,name,params,args) ret name params \
|
||||
{ return libudev.fn.udev.name ? libudev.fn.udev.name args : 0; }
|
||||
LIBUDEV_FUNCTIONS(FN_IMPL)
|
94
app/src/main.cpp
Normal file
94
app/src/main.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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 Nemo Mobile 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 "BooksDefs.h"
|
||||
#include "BooksShelf.h"
|
||||
#include "BooksBook.h"
|
||||
#include "BooksBookModel.h"
|
||||
#include "BooksCoverModel.h"
|
||||
#include "BooksConfig.h"
|
||||
#include "BooksSettings.h"
|
||||
#include "BooksImportModel.h"
|
||||
#include "BooksStorageModel.h"
|
||||
#include "BooksPageWidget.h"
|
||||
#include "BooksListWatcher.h"
|
||||
#include "BooksCoverWidget.h"
|
||||
#include "BooksTaskQueue.h"
|
||||
|
||||
#include "HarbourDebug.h"
|
||||
#include "HarbourLib.h"
|
||||
|
||||
#include "ZLibrary.h"
|
||||
|
||||
#include <sailfishapp.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QGuiApplication* app = SailfishApp::application(argc, argv);
|
||||
BOOKS_QML_REGISTER(BooksShelf, "Shelf");
|
||||
BOOKS_QML_REGISTER(BooksBook, "Book");
|
||||
BOOKS_QML_REGISTER(BooksBookModel, "BookModel");
|
||||
BOOKS_QML_REGISTER(BooksCoverModel, "CoverModel");
|
||||
BOOKS_QML_REGISTER(BooksImportModel, "BooksImportModel");
|
||||
BOOKS_QML_REGISTER(BooksStorageModel, "BookStorage");
|
||||
BOOKS_QML_REGISTER(BooksPageWidget, "PageWidget");
|
||||
BOOKS_QML_REGISTER(BooksListWatcher, "ListWatcher");
|
||||
BOOKS_QML_REGISTER(BooksCoverWidget, "BookCover");
|
||||
BOOKS_QML_REGISTER(BooksSettings, "Settings");
|
||||
HarbourLib::registerTypes(BOOKS_QML_PLUGIN,
|
||||
BOOKS_QML_PLUGIN_V1, BOOKS_QML_PLUGIN_V2);
|
||||
|
||||
QLocale locale;
|
||||
QTranslator* translator = new QTranslator(app);
|
||||
QString transDir = SailfishApp::pathTo("translations").toLocalFile();
|
||||
QString transFile(BOOKS_APP_NAME);
|
||||
if (translator->load(locale, transFile, "-", transDir) ||
|
||||
translator->load(transFile, transDir)) {
|
||||
app->installTranslator(translator);
|
||||
} else {
|
||||
HDEBUG("Failed to load translator for" << locale);
|
||||
delete translator;
|
||||
}
|
||||
|
||||
BooksConfigManager configManager;
|
||||
if (ZLibrary::init(argc, argv)) {
|
||||
ZLibrary::run(NULL);
|
||||
BooksTaskQueue::waitForDone();
|
||||
ZLibrary::shutdown();
|
||||
}
|
||||
|
||||
delete app;
|
||||
return 0;
|
||||
}
|
75
app/translations/harbour-books-ru.ts
Normal file
75
app/translations/harbour-books-ru.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="ru">
|
||||
<context>
|
||||
<name></name>
|
||||
<message id="book-font-default">
|
||||
<source>Use default fonts</source>
|
||||
<translation>Шрифты по умолчанию</translation>
|
||||
</message>
|
||||
<message id="book-font-smaller">
|
||||
<source>Use smaller fonts</source>
|
||||
<translation>Шрифты поменьше</translation>
|
||||
</message>
|
||||
<message id="book-font-larger">
|
||||
<source>Use larger fonts</source>
|
||||
<translation>Шрифты побольше</translation>
|
||||
</message>
|
||||
<message id="book-view-back">
|
||||
<source>Back to library</source>
|
||||
<translation>Вернуться в библиотеку</translation>
|
||||
</message>
|
||||
<message id="book-view-loading">
|
||||
<source>Loading...</source>
|
||||
<translation>Загрузка...</translation>
|
||||
</message>
|
||||
<message id="shelf-view-about-to-delete-all">
|
||||
<source>Deleting all books</source>
|
||||
<translation>Удаляем все книги</translation>
|
||||
</message>
|
||||
<message id="shelf-view-no-books">
|
||||
<source>No books</source>
|
||||
<translation>Здесь пусто, нет ничего вообще</translation>
|
||||
</message>
|
||||
<message id="storage-removable">
|
||||
<source>Memory card</source>
|
||||
<translation>Карта памяти</translation>
|
||||
</message>
|
||||
<message id="storage-internal">
|
||||
<source>Internal storage</source>
|
||||
<translation>Встроенная память</translation>
|
||||
</message>
|
||||
<message id="storage-book-count" numerus="yes">
|
||||
<source>%0 book(s)</source>
|
||||
<translation>
|
||||
<numerusform>%0 книга</numerusform>
|
||||
<numerusform>%0 книги</numerusform>
|
||||
<numerusform>%0 книг</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message id="storage-view-scan-downloads">
|
||||
<source>Scan downloads</source>
|
||||
<translation>Проверить загрузки</translation>
|
||||
</message>
|
||||
<message id="storage-view-delete-everything">
|
||||
<source>Delete all books</source>
|
||||
<translation>Удалить все книги</translation>
|
||||
</message>
|
||||
<message id="import-view-import-n-books" numerus="yes">
|
||||
<source>Import %0 book(s)</source>
|
||||
<translation>
|
||||
<numerusform>Взять %0 книгу</numerusform>
|
||||
<numerusform>Взять %0 книги</numerusform>
|
||||
<numerusform>Взять %0 книг</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message id="import-view-select-books">
|
||||
<source>Select books</source>
|
||||
<translation type="unfinished">Выбирайте</translation>
|
||||
</message>
|
||||
<message id="import-view-no-new-books-found">
|
||||
<source>No new books found</source>
|
||||
<translation>Новых книг не найдено, вообще ни одной</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
73
app/translations/harbour-books.ts
Normal file
73
app/translations/harbour-books.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en">
|
||||
<context>
|
||||
<name></name>
|
||||
<message id="book-font-default">
|
||||
<source>Use default fonts</source>
|
||||
<translation>Use default fonts</translation>
|
||||
</message>
|
||||
<message id="book-font-smaller">
|
||||
<source>Use smaller fonts</source>
|
||||
<translation>Use smaller fonts</translation>
|
||||
</message>
|
||||
<message id="book-font-larger">
|
||||
<source>Use larger fonts</source>
|
||||
<translation>Use larger fonts</translation>
|
||||
</message>
|
||||
<message id="book-view-back">
|
||||
<source>Back to library</source>
|
||||
<translation>Back to library</translation>
|
||||
</message>
|
||||
<message id="book-view-loading">
|
||||
<source>Loading...</source>
|
||||
<translation>Loading...</translation>
|
||||
</message>
|
||||
<message id="shelf-view-about-to-delete-all">
|
||||
<source>Deleting all books</source>
|
||||
<translation>Deleting all books</translation>
|
||||
</message>
|
||||
<message id="shelf-view-no-books">
|
||||
<source>No books</source>
|
||||
<translation>No books</translation>
|
||||
</message>
|
||||
<message id="storage-removable">
|
||||
<source>Memory card</source>
|
||||
<translation>Memory card</translation>
|
||||
</message>
|
||||
<message id="storage-internal">
|
||||
<source>Internal storage</source>
|
||||
<translation>Internal storage</translation>
|
||||
</message>
|
||||
<message id="storage-book-count" numerus="yes">
|
||||
<source>%0 book(s)</source>
|
||||
<translation>
|
||||
<numerusform>%0 book</numerusform>
|
||||
<numerusform>%0 books</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message id="storage-view-scan-downloads">
|
||||
<source>Scan downloads</source>
|
||||
<translation>Check downloads</translation>
|
||||
</message>
|
||||
<message id="storage-view-delete-everything">
|
||||
<source>Delete all books</source>
|
||||
<translation>Delete all books</translation>
|
||||
</message>
|
||||
<message id="import-view-import-n-books" numerus="yes">
|
||||
<source>Import %0 book(s)</source>
|
||||
<translation>
|
||||
<numerusform>Import %0 book</numerusform>
|
||||
<numerusform>Import %0 books</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message id="import-view-select-books">
|
||||
<source>Select books</source>
|
||||
<translation>Select books</translation>
|
||||
</message>
|
||||
<message id="import-view-no-new-books-found">
|
||||
<source>No new books found</source>
|
||||
<translation>No new books found</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
484
fbreader/fbreader.pro
Normal file
484
fbreader/fbreader.pro
Normal file
|
@ -0,0 +1,484 @@
|
|||
TEMPLATE = lib
|
||||
TARGET = fbreader
|
||||
CONFIG += staticlib object_parallel_to_source link_pkgconfig
|
||||
PKGCONFIG += expat glib-2.0
|
||||
|
||||
!include(../common.pri)
|
||||
|
||||
# Directories
|
||||
FRIBIDI_DIR = $$_PRO_FILE_PWD_/../fribidi
|
||||
LINEBREAK_DIR = $$_PRO_FILE_PWD_/../linebreak
|
||||
FBREADER_DIR = fbreader
|
||||
|
||||
DEFINES += \
|
||||
VERSION="\\\"0.99\\\"" \
|
||||
FBREADER_DISABLE_ZLFILE_PLAIN_STREAM_CACHE=1 \
|
||||
FBREADER_DISABLE_BOOKS_DB=1
|
||||
|
||||
# Core
|
||||
CORE = $$FBREADER_DIR/zlibrary/core
|
||||
CORE_SRC = $$CORE/src
|
||||
|
||||
INCLUDEPATH += $$CORE/include
|
||||
|
||||
SOURCES += \
|
||||
$$CORE_SRC/encoding/MyEncodingConverter.cpp \
|
||||
$$CORE_SRC/encoding/EncodingCollectionReader.cpp \
|
||||
$$CORE_SRC/encoding/DummyEncodingConverter.cpp \
|
||||
$$CORE_SRC/encoding/ZLEncodingSet.cpp \
|
||||
$$CORE_SRC/encoding/ZLEncodingConverter.cpp \
|
||||
$$CORE_SRC/encoding/ZLEncodingCollection.cpp \
|
||||
$$CORE_SRC/typeId/ZLTypeId.cpp \
|
||||
$$CORE_SRC/language/ZLLanguageDetector.cpp \
|
||||
$$CORE_SRC/language/ZLStatistics.cpp \
|
||||
$$CORE_SRC/language/ZLStatisticsGenerator.cpp \
|
||||
$$CORE_SRC/language/ZLStatisticsXMLReader.cpp \
|
||||
$$CORE_SRC/language/ZLStatisticsXMLWriter.cpp \
|
||||
$$CORE_SRC/language/ZLLanguageList.cpp \
|
||||
$$CORE_SRC/language/ZLCharSequence.cpp \
|
||||
$$CORE_SRC/language/ZLStatisticsItem.cpp \
|
||||
$$CORE_SRC/language/ZLLanguageMatcher.cpp \
|
||||
$$CORE_SRC/options/ZLConfig.cpp \
|
||||
$$CORE_SRC/options/ZLOptions.cpp \
|
||||
$$CORE_SRC/options/ZLCategoryKey.cpp \
|
||||
$$CORE_SRC/runnable/ZLRunnable.cpp \
|
||||
$$CORE_SRC/runnable/ZLExecutionData.cpp \
|
||||
$$CORE_SRC/application/ZLApplicationBase.cpp \
|
||||
$$CORE_SRC/application/ZLKeyBindings.cpp \
|
||||
$$CORE_SRC/util/ZLUnicodeUtil.cpp \
|
||||
$$CORE_SRC/util/ZLKeyUtil.cpp \
|
||||
$$CORE_SRC/util/ZLUserData.cpp \
|
||||
$$CORE_SRC/util/ZLFileUtil.cpp \
|
||||
$$CORE_SRC/util/ZLSearchUtil.cpp \
|
||||
$$CORE_SRC/util/ZLStringUtil.cpp \
|
||||
$$CORE_SRC/util/ZLLanguageUtil.cpp \
|
||||
$$CORE_SRC/dialogs/ZLDialogManager.cpp \
|
||||
$$CORE_SRC/dialogs/ZLDialog.cpp \
|
||||
$$CORE_SRC/dialogs/ZLOptionEntry.cpp \
|
||||
$$CORE_SRC/dialogs/ZLOptionsDialog.cpp \
|
||||
$$CORE_SRC/dialogs/ZLProgressDialog.cpp \
|
||||
$$CORE_SRC/dialogs/ZLOptionView.cpp \
|
||||
$$CORE_SRC/dialogs/ZLDialogContent.cpp \
|
||||
$$CORE_SRC/dialogs/ZLDialogContentBuilder.cpp \
|
||||
$$CORE_SRC/dialogs/ZLOpenFileDialog.cpp \
|
||||
$$CORE_SRC/time/ZLTimeManager.cpp \
|
||||
$$CORE_SRC/time/ZLTime.cpp \
|
||||
$$CORE_SRC/logger/ZLLogger.cpp \
|
||||
$$CORE_SRC/optionEntries/ZLSimpleOptionEntry.cpp \
|
||||
$$CORE_SRC/xml/ZLXMLWriter.cpp \
|
||||
$$CORE_SRC/xml/ZLXMLReader.cpp \
|
||||
$$CORE_SRC/xml/expat/ZLXMLReaderInternal.cpp \
|
||||
$$CORE_SRC/view/ZLPaintContext.cpp \
|
||||
$$CORE_SRC/view/ZLView.cpp \
|
||||
$$CORE_SRC/view/ZLMirroredPaintContext.cpp \
|
||||
$$CORE_SRC/filesystem/tar/ZLTar.cpp \
|
||||
$$CORE_SRC/filesystem/ZLInputStreamDecorator.cpp \
|
||||
$$CORE_SRC/filesystem/ZLFile.cpp \
|
||||
$$CORE_SRC/filesystem/ZLDir.cpp \
|
||||
$$CORE_SRC/filesystem/ZLFSManager.cpp \
|
||||
$$CORE_SRC/filesystem/zip/ZLZipInputStream.cpp \
|
||||
$$CORE_SRC/filesystem/zip/ZLZipDir.cpp \
|
||||
$$CORE_SRC/filesystem/zip/ZLZipEntryCache.cpp \
|
||||
$$CORE_SRC/filesystem/zip/ZLZipHeader.cpp \
|
||||
$$CORE_SRC/filesystem/zip/ZLZDecompressor.cpp \
|
||||
$$CORE_SRC/filesystem/zip/ZLGzipInputStream.cpp \
|
||||
$$CORE_SRC/filesystem/bzip2/ZLBzip2InputStream.cpp \
|
||||
$$CORE_SRC/resources/ZLResource.cpp \
|
||||
$$CORE_SRC/image/ZLBase64EncodedImage.cpp \
|
||||
$$CORE_SRC/image/ZLNetworkImage.cpp \
|
||||
$$CORE_SRC/image/ZLImage.cpp \
|
||||
$$CORE_SRC/image/ZLFileImage.cpp \
|
||||
$$CORE_SRC/image/ZLStreamImage.cpp \
|
||||
$$CORE_SRC/image/ZLImageManager.cpp \
|
||||
$$CORE_SRC/unix/iconv/IConvEncodingConverter.cpp \
|
||||
$$CORE_SRC/unix/time/ZLUnixTime.cpp \
|
||||
$$CORE_SRC/unix/filesystem/ZLUnixFSManager.cpp \
|
||||
$$CORE_SRC/unix/filesystem/ZLUnixFileInputStream.cpp \
|
||||
$$CORE_SRC/unix/filesystem/ZLUnixFSDir.cpp \
|
||||
$$CORE_SRC/unix/filesystem/ZLUnixFileOutputStream.cpp \
|
||||
$$CORE_SRC/network/ZLAsynchronousInputStream.cpp \
|
||||
$$CORE_SRC/network/ZLPlainAsynchronousInputStream.cpp \
|
||||
$$CORE_SRC/constants/ZLXMLNamespace.cpp \
|
||||
$$CORE_SRC/constants/ZLMimeType.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$CORE_SRC/encoding/EncodingCollectionReader.h \
|
||||
$$CORE_SRC/encoding/DummyEncodingConverter.h \
|
||||
$$CORE_SRC/encoding/ZLEncodingConverterProvider.h \
|
||||
$$CORE_SRC/encoding/MyEncodingConverter.h \
|
||||
$$CORE_SRC/encoding/ZLEncodingConverter.h \
|
||||
$$CORE_SRC/typeId/ZLTypeId.h \
|
||||
$$CORE_SRC/language/ZLLanguageList.h \
|
||||
$$CORE_SRC/language/ZLStatistics.h \
|
||||
$$CORE_SRC/language/ZLStatisticsGenerator.h \
|
||||
$$CORE_SRC/language/ZLLanguageMatcher.h \
|
||||
$$CORE_SRC/language/ZLLanguageDetector.h \
|
||||
$$CORE_SRC/language/ZLStatisticsXMLWriter.h \
|
||||
$$CORE_SRC/language/ZLStatisticsItem.h \
|
||||
$$CORE_SRC/language/ZLCharSequence.h \
|
||||
$$CORE_SRC/language/ZLStatisticsXMLReader.h \
|
||||
$$CORE_SRC/options/ZLOptions.h \
|
||||
$$CORE_SRC/options/ZLConfig.h \
|
||||
$$CORE_SRC/runnable/ZLExecutionData.h \
|
||||
$$CORE_SRC/runnable/ZLRunnable.h \
|
||||
$$CORE_SRC/application/ZLApplication.h \
|
||||
$$CORE_SRC/application/ZLKeyBindings.h \
|
||||
$$CORE_SRC/application/ZLApplicationWindow.h \
|
||||
$$CORE_SRC/util/ZLStringUtil.h \
|
||||
$$CORE_SRC/util/ZLUserData.h \
|
||||
$$CORE_SRC/util/ZLBoolean3.h \
|
||||
$$CORE_SRC/util/shared_ptr.h \
|
||||
$$CORE_SRC/util/ZLFileUtil.h \
|
||||
$$CORE_SRC/util/ZLColor.h \
|
||||
$$CORE_SRC/util/ZLUnicodeUtil.h \
|
||||
$$CORE_SRC/util/ZLSearchUtil.h \
|
||||
$$CORE_SRC/util/allocator.h \
|
||||
$$CORE_SRC/util/ZLKeyUtil.h \
|
||||
$$CORE_SRC/util/ZLLanguageUtil.h \
|
||||
$$CORE_SRC/dialogs/ZLOptionsDialog.h \
|
||||
$$CORE_SRC/dialogs/ZLDialogManager.h \
|
||||
$$CORE_SRC/dialogs/ZLOptionView.h \
|
||||
$$CORE_SRC/dialogs/ZLDialog.h \
|
||||
$$CORE_SRC/dialogs/ZLProgressDialog.h \
|
||||
$$CORE_SRC/dialogs/ZLOptionEntry.h \
|
||||
$$CORE_SRC/dialogs/ZLDialogContent.h \
|
||||
$$CORE_SRC/dialogs/ZLDialogContentBuilder.h \
|
||||
$$CORE_SRC/dialogs/ZLOpenFileDialog.h \
|
||||
$$CORE_SRC/library/ZLibrary.h \
|
||||
$$CORE_SRC/time/ZLTime.h \
|
||||
$$CORE_SRC/time/ZLTimeManager.h \
|
||||
$$CORE_SRC/logger/ZLLogger.h \
|
||||
$$CORE_SRC/optionEntries/ZLSimpleOptionEntry.h \
|
||||
$$CORE_SRC/xml/ZLXMLWriter.h \
|
||||
$$CORE_SRC/xml/ZLXMLReader.h \
|
||||
$$CORE_SRC/xml/expat/ZLXMLReaderInternal.h \
|
||||
$$CORE_SRC/view/ZLPaintContext.h \
|
||||
$$CORE_SRC/view/ZLMirroredPaintContext.h \
|
||||
$$CORE_SRC/view/ZLViewWidget.h \
|
||||
$$CORE_SRC/view/ZLView.h \
|
||||
$$CORE_SRC/filesystem/tar/ZLTar.h \
|
||||
$$CORE_SRC/filesystem/ZLInputStream.h \
|
||||
$$CORE_SRC/filesystem/ZLFSManager.h \
|
||||
$$CORE_SRC/filesystem/ZLDir.h \
|
||||
$$CORE_SRC/filesystem/ZLFileInfo.h \
|
||||
$$CORE_SRC/filesystem/zip/ZLZDecompressor.h \
|
||||
$$CORE_SRC/filesystem/zip/ZLZipHeader.h \
|
||||
$$CORE_SRC/filesystem/zip/ZLZip.h \
|
||||
$$CORE_SRC/filesystem/ZLOutputStream.h \
|
||||
$$CORE_SRC/filesystem/ZLFile.h \
|
||||
$$CORE_SRC/filesystem/ZLFSDir.h \
|
||||
$$CORE_SRC/filesystem/bzip2/ZLBzip2InputStream.h \
|
||||
$$CORE_SRC/resources/ZLResource.h \
|
||||
$$CORE_SRC/image/ZLImage.h \
|
||||
$$CORE_SRC/image/ZLBase64EncodedImage.h \
|
||||
$$CORE_SRC/image/ZLFileImage.h \
|
||||
$$CORE_SRC/image/ZLStreamImage.h \
|
||||
$$CORE_SRC/image/ZLImageManager.h \
|
||||
$$CORE_SRC/image/ZLNetworkImage.h \
|
||||
$$CORE_SRC/unix/iconv/IConvEncodingConverter.h \
|
||||
$$CORE_SRC/unix/library/ZLibraryImplementation.h \
|
||||
$$CORE_SRC/unix/time/ZLUnixTime.h \
|
||||
$$CORE_SRC/unix/filesystem/ZLUnixFSManager.h \
|
||||
$$CORE_SRC/unix/filesystem/ZLUnixFileInputStream.h \
|
||||
$$CORE_SRC/unix/filesystem/ZLUnixFileOutputStream.h \
|
||||
$$CORE_SRC/unix/filesystem/ZLUnixFSDir.h \
|
||||
$$CORE_SRC/network/ZLAsynchronousInputStream.h \
|
||||
$$CORE_SRC/network/ZLPlainAsynchronousInputStream.h \
|
||||
$$CORE_SRC/constants/ZLMimeType.h \
|
||||
$$CORE_SRC/constants/ZLXMLNamespace.h
|
||||
|
||||
# Text
|
||||
TEXT = $$FBREADER_DIR/zlibrary/text
|
||||
TEXT_SRC = $$TEXT/src
|
||||
|
||||
INCLUDEPATH += \
|
||||
$$TEXT/include \
|
||||
$$LINEBREAK_DIR/include \
|
||||
$$FRIBIDI_DIR/include
|
||||
|
||||
SOURCES += \
|
||||
$$TEXT_SRC/style/ZLTextStyle.cpp \
|
||||
$$TEXT_SRC/style/ZLTextDecoratedStyle.cpp \
|
||||
$$TEXT_SRC/style/ZLTextStyleCollection.cpp \
|
||||
$$TEXT_SRC/model/ZLTextModel.cpp \
|
||||
$$TEXT_SRC/model/ZLTextParagraph.cpp \
|
||||
$$TEXT_SRC/model/ZLTextRowMemoryAllocator.cpp \
|
||||
$$TEXT_SRC/hyphenation/ZLTextTeXHyphenator.cpp \
|
||||
$$TEXT_SRC/hyphenation/ZLTextHyphenator.cpp \
|
||||
$$TEXT_SRC/hyphenation/ZLTextHyphenationReader.cpp \
|
||||
$$TEXT_SRC/view/ZLTextPositionIndicator.cpp \
|
||||
$$TEXT_SRC/view/ZLTextSelectionScroller.cpp \
|
||||
$$TEXT_SRC/view/ZLTextView_paint.cpp \
|
||||
$$TEXT_SRC/view/ZLTextView.cpp \
|
||||
$$TEXT_SRC/area/ZLTextArea.cpp \
|
||||
$$TEXT_SRC/area/ZLTextArea_processTextLine.cpp \
|
||||
$$TEXT_SRC/area/ZLTextArea_drawTextLine.cpp \
|
||||
$$TEXT_SRC/area/ZLTextAreaController.cpp \
|
||||
$$TEXT_SRC/area/ZLTextParagraphBuilder.cpp \
|
||||
$$TEXT_SRC/area/ZLTextParagraphCursor.cpp \
|
||||
$$TEXT_SRC/area/ZLTextWord.cpp \
|
||||
$$TEXT_SRC/area/ZLTextElement.cpp \
|
||||
$$TEXT_SRC/area/ZLTextAreaStyle.cpp \
|
||||
$$TEXT_SRC/area/ZLTextArea_drawWord.cpp \
|
||||
$$TEXT_SRC/area/ZLTextArea_drawTreeLines.cpp \
|
||||
$$TEXT_SRC/area/ZLTextArea_prepareTextLine.cpp \
|
||||
$$TEXT_SRC/area/ZLTextSelectionModel.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$TEXT_SRC/style/ZLTextStyleCollection.h \
|
||||
$$TEXT_SRC/style/ZLTextStyle.h \
|
||||
$$TEXT_SRC/style/ZLTextDecoratedStyle.h \
|
||||
$$TEXT_SRC/model/ZLTextAlignmentType.h \
|
||||
$$TEXT_SRC/model/ZLTextFontModifier.h \
|
||||
$$TEXT_SRC/model/ZLTextParagraph.h \
|
||||
$$TEXT_SRC/model/ZLTextModel.h \
|
||||
$$TEXT_SRC/model/ZLTextMark.h \
|
||||
$$TEXT_SRC/model/ZLTextRowMemoryAllocator.h \
|
||||
$$TEXT_SRC/model/ZLTextKind.h \
|
||||
$$TEXT_SRC/hyphenation/ZLTextHyphenator.h \
|
||||
$$TEXT_SRC/hyphenation/ZLTextHyphenationReader.h \
|
||||
$$TEXT_SRC/hyphenation/ZLTextTeXHyphenator.h \
|
||||
$$TEXT_SRC/view/ZLTextView.h \
|
||||
$$TEXT_SRC/view/ZLTextPositionIndicatorInfo.h \
|
||||
$$TEXT_SRC/view/ZLTextPositionIndicator.h \
|
||||
$$TEXT_SRC/view/ZLTextSelectionScroller.h \
|
||||
$$TEXT_SRC/area/ZLTextWord.h \
|
||||
$$TEXT_SRC/area/ZLTextElement.h \
|
||||
$$TEXT_SRC/area/ZLTextRectangle.h \
|
||||
$$TEXT_SRC/area/ZLTextAreaStyle.h \
|
||||
$$TEXT_SRC/area/ZLTextParagraphBuilder.h \
|
||||
$$TEXT_SRC/area/ZLTextAreaController.h \
|
||||
$$TEXT_SRC/area/ZLTextLineInfo.h \
|
||||
$$TEXT_SRC/area/ZLTextSelectionModel.h \
|
||||
$$TEXT_SRC/area/ZLTextParagraphCursor.h \
|
||||
$$TEXT_SRC/area/ZLTextArea.h
|
||||
|
||||
# UI
|
||||
|
||||
UI_SRC = $$FBREADER_DIR/zlibrary/ui/src/qt4
|
||||
|
||||
SOURCES += \
|
||||
$$UI_SRC/time/ZLQtTime.cpp \
|
||||
$$UI_SRC/filesystem/ZLQtFSManager.cpp \
|
||||
$$UI_SRC/image/ZLQtImageManager.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$UI_SRC/time/ZLQtTime.h \
|
||||
$$UI_SRC/filesystem/ZLQtFSManager.h \
|
||||
$$UI_SRC/image/ZLQtImageManager.h
|
||||
|
||||
# FBReader
|
||||
|
||||
FBREADER_SRC = $$FBREADER_DIR/fbreader/src
|
||||
|
||||
SOURCES += \
|
||||
$$FBREADER_SRC/migration/BookInfo.cpp \
|
||||
$$FBREADER_SRC/options/FBOptions.cpp \
|
||||
$$FBREADER_SRC/options/FBCategoryKey.cpp \
|
||||
$$FBREADER_SRC/libraryActions/AuthorInfoDialog.cpp \
|
||||
$$FBREADER_SRC/libraryActions/LibraryTagActions.cpp \
|
||||
$$FBREADER_SRC/libraryActions/LibraryBookActions.cpp \
|
||||
$$FBREADER_SRC/libraryActions/LibraryAuthorActions.cpp \
|
||||
$$FBREADER_SRC/libraryActions/BooksUtil.cpp \
|
||||
$$FBREADER_SRC/fbreader/PreferencesPopupData.cpp \
|
||||
$$FBREADER_SRC/fbreader/FBReaderActions.cpp \
|
||||
$$FBREADER_SRC/fbreader/TimeUpdater.cpp \
|
||||
$$FBREADER_SRC/fbreader/SearchActions.cpp \
|
||||
$$FBREADER_SRC/fbreader/ContentsView.cpp \
|
||||
$$FBREADER_SRC/fbreader/BooksOrderAction.cpp \
|
||||
$$FBREADER_SRC/fbreader/BookTextView.cpp \
|
||||
$$FBREADER_SRC/fbreader/FBReaderActionCode.cpp \
|
||||
$$FBREADER_SRC/fbreader/RecentBooksPopupData.cpp \
|
||||
$$FBREADER_SRC/fbreader/SearchOnNetworkAction.cpp \
|
||||
$$FBREADER_SRC/fbreader/ScrollingAction.cpp \
|
||||
$$FBREADER_SRC/fbreader/AddBookAction.cpp \
|
||||
$$FBREADER_SRC/library/Book.cpp \
|
||||
$$FBREADER_SRC/library/Comparators.cpp \
|
||||
$$FBREADER_SRC/library/Library.cpp \
|
||||
$$FBREADER_SRC/library/Tag.cpp \
|
||||
$$FBREADER_SRC/library/Author.cpp \
|
||||
$$FBREADER_SRC/formats/dummy/DummyBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/dummy/DummyMetaInfoReader.cpp \
|
||||
$$FBREADER_SRC/formats/fb2/FB2MetaInfoReader.cpp \
|
||||
$$FBREADER_SRC/formats/fb2/FB2TagManager.cpp \
|
||||
$$FBREADER_SRC/formats/fb2/FB2Plugin.cpp \
|
||||
$$FBREADER_SRC/formats/fb2/FB2Reader.cpp \
|
||||
$$FBREADER_SRC/formats/fb2/FB2BookReader.cpp \
|
||||
$$FBREADER_SRC/formats/fb2/FB2CoverReader.cpp \
|
||||
$$FBREADER_SRC/formats/openreader/OpenReaderPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/openreader/ORDescriptionReader.cpp \
|
||||
$$FBREADER_SRC/formats/openreader/ORBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/util/TextFormatDetector.cpp \
|
||||
$$FBREADER_SRC/formats/util/EntityFilesCollector.cpp \
|
||||
$$FBREADER_SRC/formats/util/MiscUtil.cpp \
|
||||
$$FBREADER_SRC/formats/util/XMLTextStream.cpp \
|
||||
$$FBREADER_SRC/formats/util/MergedStream.cpp \
|
||||
$$FBREADER_SRC/formats/FormatPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/EncodedTextReader.cpp \
|
||||
$$FBREADER_SRC/formats/css/StyleSheetParser.cpp \
|
||||
$$FBREADER_SRC/formats/css/StyleSheetTable.cpp \
|
||||
$$FBREADER_SRC/formats/tcr/TcrPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/tcr/TcrStream.cpp \
|
||||
$$FBREADER_SRC/formats/tcr/PPLBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/rtf/RtfReaderStream.cpp \
|
||||
$$FBREADER_SRC/formats/rtf/RtfBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/rtf/RtfReader.cpp \
|
||||
$$FBREADER_SRC/formats/rtf/RtfDescriptionReader.cpp \
|
||||
$$FBREADER_SRC/formats/rtf/RtfPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/rtf/RtfImage.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PmlBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PalmDocLikePlugin.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/HuffDecompressor.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/EReaderStream.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/MobipocketPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PluckerBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PalmDocLikeStream.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PluckerImages.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PdbStream.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PmlReader.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/BitReader.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PluckerTextStream.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/MobipocketHtmlBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/ZTXTStream.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/ZTXTPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PdbPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/HtmlMetainfoReader.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PdbReader.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PalmDocStream.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PalmDocPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/DocDecompressor.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/SimplePdbPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/PluckerPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/pdb/EReaderPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/xhtml/XHTMLReader.cpp \
|
||||
$$FBREADER_SRC/formats/oeb/OEBPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/oeb/OEBMetaInfoReader.cpp \
|
||||
$$FBREADER_SRC/formats/oeb/OEBCoverReader.cpp \
|
||||
$$FBREADER_SRC/formats/oeb/OEBTextStream.cpp \
|
||||
$$FBREADER_SRC/formats/oeb/OEBBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/oeb/NCXReader.cpp \
|
||||
$$FBREADER_SRC/formats/PluginCollection.cpp \
|
||||
$$FBREADER_SRC/formats/html/HtmlPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/html/HtmlReaderStream.cpp \
|
||||
$$FBREADER_SRC/formats/html/HtmlEntityCollection.cpp \
|
||||
$$FBREADER_SRC/formats/html/HtmlBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/html/HtmlDescriptionReader.cpp \
|
||||
$$FBREADER_SRC/formats/html/HtmlReader.cpp \
|
||||
$$FBREADER_SRC/formats/chm/CHMFileImage.cpp \
|
||||
$$FBREADER_SRC/formats/chm/HHCReferenceCollector.cpp \
|
||||
$$FBREADER_SRC/formats/chm/CHMReferenceCollection.cpp \
|
||||
$$FBREADER_SRC/formats/chm/BitStream.cpp \
|
||||
$$FBREADER_SRC/formats/chm/HtmlSectionReader.cpp \
|
||||
$$FBREADER_SRC/formats/chm/LZXDecompressor.cpp \
|
||||
$$FBREADER_SRC/formats/chm/HuffmanDecoder.cpp \
|
||||
$$FBREADER_SRC/formats/chm/CHMFile.cpp \
|
||||
$$FBREADER_SRC/formats/chm/HHCReader.cpp \
|
||||
$$FBREADER_SRC/formats/chm/CHMPlugin.cpp \
|
||||
$$FBREADER_SRC/formats/chm/E8Decoder.cpp \
|
||||
$$FBREADER_SRC/formats/txt/TxtReader.cpp \
|
||||
$$FBREADER_SRC/formats/txt/PlainTextFormat.cpp \
|
||||
$$FBREADER_SRC/formats/txt/TxtBookReader.cpp \
|
||||
$$FBREADER_SRC/formats/txt/TxtPlugin.cpp \
|
||||
$$FBREADER_SRC/bookmodel/BookReader.cpp \
|
||||
$$FBREADER_SRC/bookmodel/BookModel.cpp \
|
||||
|
||||
HEADERS += \
|
||||
$$FBREADER_SRC/migration/BookInfo.h \
|
||||
$$FBREADER_SRC/options/FBOptions.h \
|
||||
$$FBREADER_SRC/libraryActions/LibraryAuthorActions.h \
|
||||
$$FBREADER_SRC/libraryActions/AuthorInfoDialog.h \
|
||||
$$FBREADER_SRC/libraryActions/LibraryBookActions.h \
|
||||
$$FBREADER_SRC/libraryActions/BooksUtil.h \
|
||||
$$FBREADER_SRC/libraryActions/LibraryTagActions.h \
|
||||
$$FBREADER_SRC/fbreader/FBView.h \
|
||||
$$FBREADER_SRC/fbreader/ReadingState.h \
|
||||
$$FBREADER_SRC/fbreader/FBReaderActions.h \
|
||||
$$FBREADER_SRC/fbreader/PreferencesPopupData.h \
|
||||
$$FBREADER_SRC/fbreader/TimeUpdater.h \
|
||||
$$FBREADER_SRC/fbreader/ContentsView.h \
|
||||
$$FBREADER_SRC/fbreader/RecentBooksPopupData.h \
|
||||
$$FBREADER_SRC/fbreader/FootnoteView.h \
|
||||
$$FBREADER_SRC/fbreader/ScrollingAction.h \
|
||||
$$FBREADER_SRC/fbreader/BookTextView.h \
|
||||
$$FBREADER_SRC/library/Author.h \
|
||||
$$FBREADER_SRC/library/Book.h \
|
||||
$$FBREADER_SRC/library/Lists.h \
|
||||
$$FBREADER_SRC/library/Library.h \
|
||||
$$FBREADER_SRC/library/Tag.h \
|
||||
$$FBREADER_SRC/formats/dummy/DummyBookReader.h \
|
||||
$$FBREADER_SRC/formats/dummy/DummyMetaInfoReader.h \
|
||||
$$FBREADER_SRC/formats/fb2/FB2Plugin.h \
|
||||
$$FBREADER_SRC/formats/fb2/FB2MetaInfoReader.h \
|
||||
$$FBREADER_SRC/formats/fb2/FB2TagManager.h \
|
||||
$$FBREADER_SRC/formats/fb2/FB2BookReader.h \
|
||||
$$FBREADER_SRC/formats/fb2/FB2Reader.h \
|
||||
$$FBREADER_SRC/formats/fb2/FB2CoverReader.h \
|
||||
$$FBREADER_SRC/formats/openreader/OpenReaderPlugin.h \
|
||||
$$FBREADER_SRC/formats/openreader/ORDescriptionReader.h \
|
||||
$$FBREADER_SRC/formats/openreader/ORBookReader.h \
|
||||
$$FBREADER_SRC/formats/EncodedTextReader.h \
|
||||
$$FBREADER_SRC/formats/util/TextFormatDetector.h \
|
||||
$$FBREADER_SRC/formats/util/MergedStream.h \
|
||||
$$FBREADER_SRC/formats/util/MiscUtil.h \
|
||||
$$FBREADER_SRC/formats/util/EntityFilesCollector.h \
|
||||
$$FBREADER_SRC/formats/util/XMLTextStream.h \
|
||||
$$FBREADER_SRC/formats/css/StyleSheetParser.h \
|
||||
$$FBREADER_SRC/formats/css/StyleSheetTable.h \
|
||||
$$FBREADER_SRC/formats/tcr/TcrStream.h \
|
||||
$$FBREADER_SRC/formats/tcr/TcrPlugin.h \
|
||||
$$FBREADER_SRC/formats/tcr/PPLBookReader.h \
|
||||
$$FBREADER_SRC/formats/rtf/RtfPlugin.h \
|
||||
$$FBREADER_SRC/formats/rtf/RtfBookReader.h \
|
||||
$$FBREADER_SRC/formats/rtf/RtfReader.h \
|
||||
$$FBREADER_SRC/formats/rtf/RtfReaderStream.h \
|
||||
$$FBREADER_SRC/formats/rtf/RtfImage.h \
|
||||
$$FBREADER_SRC/formats/rtf/RtfDescriptionReader.h \
|
||||
$$FBREADER_SRC/formats/FormatPlugin.h \
|
||||
$$FBREADER_SRC/formats/pdb/ZTXTStream.h \
|
||||
$$FBREADER_SRC/formats/pdb/PalmDocStream.h \
|
||||
$$FBREADER_SRC/formats/pdb/PdbReader.h \
|
||||
$$FBREADER_SRC/formats/pdb/PmlBookReader.h \
|
||||
$$FBREADER_SRC/formats/pdb/PdbStream.h \
|
||||
$$FBREADER_SRC/formats/pdb/PluckerImages.h \
|
||||
$$FBREADER_SRC/formats/pdb/PalmDocLikeStream.h \
|
||||
$$FBREADER_SRC/formats/pdb/HtmlMetainfoReader.h \
|
||||
$$FBREADER_SRC/formats/pdb/MobipocketHtmlBookReader.h \
|
||||
$$FBREADER_SRC/formats/pdb/BitReader.h \
|
||||
$$FBREADER_SRC/formats/pdb/HuffDecompressor.h \
|
||||
$$FBREADER_SRC/formats/pdb/DocDecompressor.h \
|
||||
$$FBREADER_SRC/formats/pdb/PmlReader.h \
|
||||
$$FBREADER_SRC/formats/pdb/PluckerBookReader.h \
|
||||
$$FBREADER_SRC/formats/pdb/PdbPlugin.h \
|
||||
$$FBREADER_SRC/formats/pdb/EReaderStream.h \
|
||||
$$FBREADER_SRC/formats/pdb/PluckerTextStream.h \
|
||||
$$FBREADER_SRC/formats/xhtml/XHTMLReader.h \
|
||||
$$FBREADER_SRC/formats/oeb/OEBBookReader.h \
|
||||
$$FBREADER_SRC/formats/oeb/OEBTextStream.h \
|
||||
$$FBREADER_SRC/formats/oeb/OEBPlugin.h \
|
||||
$$FBREADER_SRC/formats/oeb/NCXReader.h \
|
||||
$$FBREADER_SRC/formats/oeb/OEBMetaInfoReader.h \
|
||||
$$FBREADER_SRC/formats/oeb/OEBCoverReader.h \
|
||||
$$FBREADER_SRC/formats/html/HtmlPlugin.h \
|
||||
$$FBREADER_SRC/formats/html/HtmlEntityCollection.h \
|
||||
$$FBREADER_SRC/formats/html/HtmlReaderStream.h \
|
||||
$$FBREADER_SRC/formats/html/HtmlReader.h \
|
||||
$$FBREADER_SRC/formats/html/HtmlTagActions.h \
|
||||
$$FBREADER_SRC/formats/html/HtmlBookReader.h \
|
||||
$$FBREADER_SRC/formats/html/HtmlDescriptionReader.h \
|
||||
$$FBREADER_SRC/formats/chm/CHMPlugin.h \
|
||||
$$FBREADER_SRC/formats/chm/CHMFile.h \
|
||||
$$FBREADER_SRC/formats/chm/LZXDecompressor.h \
|
||||
$$FBREADER_SRC/formats/chm/CHMFileImage.h \
|
||||
$$FBREADER_SRC/formats/chm/HHCReferenceCollector.h \
|
||||
$$FBREADER_SRC/formats/chm/HtmlSectionReader.h \
|
||||
$$FBREADER_SRC/formats/chm/CHMReferenceCollection.h \
|
||||
$$FBREADER_SRC/formats/chm/HuffmanDecoder.h \
|
||||
$$FBREADER_SRC/formats/chm/BitStream.h \
|
||||
$$FBREADER_SRC/formats/chm/HHCReader.h \
|
||||
$$FBREADER_SRC/formats/txt/TxtBookReader.h \
|
||||
$$FBREADER_SRC/formats/txt/PlainTextFormat.h \
|
||||
$$FBREADER_SRC/formats/txt/TxtPlugin.h \
|
||||
$$FBREADER_SRC/formats/txt/TxtReader.h \
|
||||
$$FBREADER_SRC/bookmodel/FBTextKind.h \
|
||||
$$FBREADER_SRC/bookmodel/BookModel.h \
|
||||
$$FBREADER_SRC/bookmodel/BookReader.h
|
6
harbour-books.pro
Normal file
6
harbour-books.pro
Normal file
|
@ -0,0 +1,6 @@
|
|||
TEMPLATE = subdirs
|
||||
CONFIG += ordered
|
||||
SUBDIRS = fribidi linebreak fbreader harbour-lib app
|
||||
|
||||
OTHER_FILES += \
|
||||
rpm/harbour-books.spec
|
1
harbour-lib
Submodule
1
harbour-lib
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 24f9fe58d06dba0982aa7c3eecce461dbc3f7d6d
|
56
rpm/harbour-books.spec
Normal file
56
rpm/harbour-books.spec
Normal file
|
@ -0,0 +1,56 @@
|
|||
Name: harbour-books
|
||||
Summary: E-book reader
|
||||
Version: 1.0.0
|
||||
Release: 1
|
||||
License: GPL
|
||||
Group: Applications/File
|
||||
URL: http://github.com/monich/harbour-books
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
Requires: sailfishsilica-qt5
|
||||
BuildRequires: pkgconfig(glib-2.0)
|
||||
BuildRequires: pkgconfig(sailfishapp)
|
||||
BuildRequires: pkgconfig(Qt5Quick)
|
||||
BuildRequires: pkgconfig(Qt5Core)
|
||||
BuildRequires: pkgconfig(Qt5Svg)
|
||||
BuildRequires: pkgconfig(Qt5Qml)
|
||||
BuildRequires: pkgconfig(mlite5)
|
||||
BuildRequires: pkgconfig(expat)
|
||||
BuildRequires: pkgconfig(systemd)
|
||||
BuildRequires: bzip2-devel
|
||||
BuildRequires: desktop-file-utils
|
||||
BuildRequires: qt5-qttools-linguist
|
||||
|
||||
%{!?qtc_qmake5:%define qtc_qmake5 %qmake5}
|
||||
%{!?qtc_make:%define qtc_make make}
|
||||
%{?qtc_builddir:%define _builddir %qtc_builddir}
|
||||
|
||||
%description
|
||||
FBReader-based e-book reader.
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name}-%{version}
|
||||
|
||||
%build
|
||||
%qtc_qmake5 harbour-books.pro
|
||||
%qtc_make %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
cd app
|
||||
%qmake5_install
|
||||
|
||||
desktop-file-install --delete-original \
|
||||
--dir %{buildroot}%{_datadir}/applications \
|
||||
%{buildroot}%{_datadir}/applications/*.desktop
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_bindir}/%{name}
|
||||
%{_datadir}/%{name}
|
||||
%{_datadir}/applications/%{name}.desktop
|
||||
%{_datadir}/icons/hicolor/86x86/apps/%{name}.png
|
||||
|
||||
%changelog
|
||||
* Thu May 14 2015 Slava Monich <slava.monich@jolla.com> 1.0.0
|
||||
- Initial version
|
Loading…
Reference in a new issue