diff options
Diffstat (limited to 'src/mobile')
67 files changed, 6304 insertions, 0 deletions
diff --git a/src/mobile/bibletime.cpp b/src/mobile/bibletime.cpp new file mode 100644 index 0000000..dd32bf4 --- /dev/null +++ b/src/mobile/bibletime.cpp @@ -0,0 +1,101 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "bibletime.h" + +#include "backend/config/btconfig.h" +#include "backend/managers/btstringmgr.h" +#include "backend/managers/clanguagemgr.h" +#include "backend/managers/cswordbackend.h" +#include <QLocale> +#include <stringmgr.h> +#include <swlog.h> + +namespace btm { + +BibleTime::BibleTime(QObject* parent) + : QObject(parent) { + initBackends(); +} + + +/** Initializes the backend */ +void BibleTime::initBackends() { + initSwordConfigFile(); + + sword::StringMgr::setSystemStringMgr( new BtStringMgr() ); + sword::SWLog::getSystemLog()->setLogLevel(sword::SWLog::LOG_ERROR); + + if (qApp->property("--debug").toBool()) { + sword::SWLog::getSystemLog()->setLogLevel(sword::SWLog::LOG_DEBUG); + } + +#ifdef Q_OS_MAC + // set a LocaleMgr with a fixed path to the locales.d of the DMG image on MacOS + // note: this must be done after setting the BTStringMgr, because this will reset the LocaleMgr + qDebug() << "Using sword locales dir: " << util::directory::getSwordLocalesDir().absolutePath().toUtf8(); + sword::LocaleMgr::setSystemLocaleMgr(new sword::LocaleMgr(util::directory::getSwordLocalesDir().absolutePath().toUtf8())); +#endif + + CSwordBackend *backend = CSwordBackend::createInstance(); + QString systemName = QLocale::system().name(); + QString language = btConfig().value<QString>("language", systemName); + backend->booknameLanguage(language); + + const CSwordBackend::LoadError errorCode = CSwordBackend::instance()->initModules(CSwordBackend::OtherChange); + if (errorCode != CSwordBackend::NoError) { + ; // TODO + } +} + +void BibleTime::initSwordConfigFile() { +// On Windows the sword.conf must be created before the initialization of sword +// It will contain the LocalePath which is used for sword locales +// It also contains a DataPath to the %ALLUSERSPROFILE%\Sword directory +// If this is not done here, the sword locales.d won't be found +#ifdef Q_OS_WIN + QString configFile = util::directory::getUserHomeSwordDir().filePath("sword.conf"); + QFile file(configFile); + if (file.exists()) { + return; + } + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + return; + } + QTextStream out(&file); + out << "\n"; + out << "[Install]\n"; + out << "DataPath=" << util::directory::convertDirSeparators( util::directory::getSharedSwordDir().absolutePath()) << "\n"; + out << "LocalePath=" << util::directory::convertDirSeparators(util::directory::getApplicationSwordDir().absolutePath()) << "\n"; + out << "\n"; + file.close(); +#endif + +#ifdef Q_OS_MAC + QString configFile = util::directory::getUserHomeSwordDir().filePath("sword.conf"); + QFile file(configFile); + if (file.exists()) { + return; + } + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + return; + } + QTextStream out(&file); + out << "\n"; + out << "[Install]\n"; + out << "DataPath=" << util::directory::convertDirSeparators( util::directory::getUserHomeSwordDir().absolutePath()) << "\n"; + out << "\n"; + file.close(); +#endif +} + +} diff --git a/src/mobile/bibletime.h b/src/mobile/bibletime.h new file mode 100644 index 0000000..b424571 --- /dev/null +++ b/src/mobile/bibletime.h @@ -0,0 +1,31 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#pragma once + +#include <QObject> + +namespace btm { + +class BibleTime : public QObject { + Q_OBJECT + +public: + BibleTime(QObject* parent = 0); + +private: + void initBackends(); + void initSwordConfigFile(); + +}; + +} diff --git a/src/mobile/bibletimeapp.cpp b/src/mobile/bibletimeapp.cpp new file mode 100644 index 0000000..f7801b8 --- /dev/null +++ b/src/mobile/bibletimeapp.cpp @@ -0,0 +1,95 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "bibletimeapp.h" + +#include <QDebug> +#include <QFile> +#include "backend/config/btconfig.h" +#include "backend/managers/cswordbackend.h" +#include "backend/managers/cdisplaytemplatemgr.h" +#include "frontend/messagedialog.h" +#include "util/cresmgr.h" +#include "util/geticon.h" +#include "util/directory.h" + + +BibleTimeApp::BibleTimeApp(int &argc, char **argv) + : QGuiApplication(argc, argv) + , m_init(false) { + setApplicationName("bibletime"); + setApplicationVersion(BT_VERSION); +} + +BibleTimeApp::~BibleTimeApp() { + // Prevent writing to the log file before the directory cache is init: + if (!m_init || BtConfig::m_instance == 0) + return; + + //we can set this safely now because we close now (hopyfully without crash) + btConfig().setValue("state/crashedLastTime", false); + btConfig().setValue("state/crashedTwoTimes", false); + + delete CDisplayTemplateMgr::instance(); + CLanguageMgr::destroyInstance(); + CSwordBackend::destroyInstance(); + util::clearIconCache(); + + BtConfig::destroyInstance(); +} + +bool BibleTimeApp::initBtConfig() { + Q_ASSERT(m_init); + + return BtConfig::initBtConfig(); +} + +bool BibleTimeApp::initDisplayTemplateManager() { + Q_ASSERT(m_init); + + QString errorMessage; + new CDisplayTemplateMgr(errorMessage); + if (errorMessage.isNull()) + return true; + message::showCritical(0, tr("Fatal error!"), errorMessage); + return false; +} + + +const QIcon & BibleTimeApp::getIcon(const QString & name) const { + QString plainName(name); + if (plainName.endsWith(".svg", Qt::CaseInsensitive)) + plainName.chop(4); + + const QMap<QString, QIcon>::const_iterator i = m_iconCache.find(plainName); + if (i != m_iconCache.end()) + return *i; + + const QString iconDir = util::directory::getIconDir().canonicalPath(); + QString iconFileName = iconDir + "/" + plainName + ".svg"; + if (QFile(iconFileName).exists()) + return *m_iconCache.insert(plainName, QIcon(iconFileName)); + + iconFileName = iconDir + "/" + plainName + ".png"; + if (QFile(iconFileName).exists()) + return *m_iconCache.insert(plainName, QIcon(iconFileName)); + + if (plainName != "default") { + qWarning() << "Cannot find icon file" << iconFileName + << ", using default icon."; + return getIcon("default"); + } + + qWarning() << "Cannot find default icon" << iconFileName + << ", using null icon."; + return m_nullIcon; +} diff --git a/src/mobile/bibletimeapp.h b/src/mobile/bibletimeapp.h new file mode 100644 index 0000000..08cd0a5 --- /dev/null +++ b/src/mobile/bibletimeapp.h @@ -0,0 +1,55 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#ifndef BIBLETIMEAPP_H +#define BIBLETIMEAPP_H + +#include <QGuiApplication> +#include <QIcon> +#include <QMap> + + +/** + The BibleTimeApp class is used to clean up all instances of the backend and to + delete all created module objects. +*/ +class BibleTimeApp : public QGuiApplication { + + Q_OBJECT + + public: /* Methods: */ + + BibleTimeApp(int &argc, char **argv); + ~BibleTimeApp(); + + inline void startInit() { m_init = true; } + bool initBtConfig(); + bool initDisplayTemplateManager(); + + /** + \param[in] name the name of the icon to return. + \returns a reference to the icon with the given name or to a NULL + icon if no such icon is found. + */ + const QIcon & getIcon(const QString & name) const; + + private: /* Fields: */ + + mutable QMap<QString, QIcon> m_iconCache; + const QIcon m_nullIcon; + bool m_init; + +}; + +#define bApp (static_cast<BibleTimeApp *>(QCoreApplication::instance())) + +#endif diff --git a/src/mobile/bookshelfmanager/installmanager.cpp b/src/mobile/bookshelfmanager/installmanager.cpp new file mode 100644 index 0000000..99a72a0 --- /dev/null +++ b/src/mobile/bookshelfmanager/installmanager.cpp @@ -0,0 +1,371 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "installmanager.h" + +#include "backend/btinstallbackend.h" +#include "backend/managers/clanguagemgr.h" +#include "backend/btinstallmgr.h" +#include "mobile/btmmain.h" +#include "mobile/ui/qtquick2applicationviewer.h" +#include "mobile/ui/viewmanager.h" +#include <QDebug> +#include <QQuickItem> +#include <QtAlgorithms> + +namespace btm { + +enum TextRoles { + TextRole = Qt::UserRole + 1 +}; + +enum WorksRoles { + TitleRole = Qt::UserRole + 1, + DescriptionRole = Qt::UserRole + 2, + InstalledRole = Qt::UserRole + 3 +}; + +static bool moduleInstalled(const CSwordModuleInfo& moduleInfo) { + const CSwordModuleInfo *installedModule = CSwordBackend::instance()->findModuleByName(moduleInfo.name()); + return installedModule != 0; +} + +static void setupTextModel(const QStringList& modelList, RoleItemModel* model) { + QHash<int, QByteArray> roleNames; + roleNames[TextRole] = "modelText"; + model->setRoleNames(roleNames); + + model->clear(); + for (int i=0; i< modelList.count(); ++i) { + QString source = modelList.at(i); + QStandardItem* item = new QStandardItem(); + item->setData(source, TextRole); + model->appendRow(item); + } +} + +static void setupWorksModel(const QStringList& titleList, + const QStringList& descriptionList, + const QList<int>& installedList, + RoleItemModel* model) { + Q_ASSERT(titleList.count() == descriptionList.count()); + Q_ASSERT(titleList.count() == installedList.count()); + + QHash<int, QByteArray> roleNames; + roleNames[TitleRole] = "title"; + roleNames[DescriptionRole] = "desc"; + roleNames[InstalledRole] = "installed"; + model->setRoleNames(roleNames); + + model->clear(); + for (int i=0; i< titleList.count(); ++i) { + QStandardItem* item = new QStandardItem(); + QString title = titleList.at(i); + item->setData(title, TitleRole); + QString description = descriptionList.at(i); + item->setData(description, DescriptionRole); + int installed = installedList.at(i); + item->setData(installed, InstalledRole); + model->appendRow(item); + } +} + +InstallManager::InstallManager(QObject* /* parent */) + : m_installManagerChooserObject(0), + m_btInstallMgr(0) { +} + +void InstallManager::openChooser() { + + if (m_installManagerChooserObject == 0) + findInstallManagerObject(); + if (m_installManagerChooserObject == 0) + return; + + setupSourceModel(); + makeConnections(); + setProperties(); + sourceIndexChanged(0); +} + +void InstallManager::findInstallManagerObject() { + + QtQuick2ApplicationViewer* viewer = getViewManager()->getViewer(); + QQuickItem * rootObject = 0; + if (viewer != 0) + rootObject = viewer->rootObject(); + if (rootObject != 0) + m_installManagerChooserObject = rootObject->findChild<QQuickItem*>("installManagerChooser"); +} + +void InstallManager::findProgressObject() { + QtQuick2ApplicationViewer* viewer = getViewManager()->getViewer(); + QQuickItem * rootObject = 0; + if (viewer != 0) + rootObject = viewer->rootObject(); + if (rootObject != 0) + m_progressObject = rootObject->findChild<QQuickItem*>("progress"); +} + + +void InstallManager::setupSourceModel() { + m_sourceList = BtInstallBackend::sourceNameList(); + setupTextModel(m_sourceList, &m_sourceModel); +} + +void InstallManager::makeConnections() +{ + m_installManagerChooserObject->disconnect(); + + bool ok = connect(m_installManagerChooserObject, SIGNAL(sourceChanged(int)), + this, SLOT(sourceIndexChanged(int))); + Q_ASSERT(ok); + + ok = connect(m_installManagerChooserObject, SIGNAL(categoryChanged(int)), + this, SLOT(categoryIndexChanged(int))); + Q_ASSERT(ok); + + ok = connect(m_installManagerChooserObject, SIGNAL(languageChanged(int)), + this, SLOT(languageIndexChanged(int))); + Q_ASSERT(ok); + + ok = connect(m_installManagerChooserObject, SIGNAL(workSelected(int)), + this, SLOT(workSelected(int))); + Q_ASSERT(ok); + + ok = connect(m_installManagerChooserObject, SIGNAL(cancel()), + this, SLOT(cancel())); + Q_ASSERT(ok); + + ok = connect(m_installManagerChooserObject, SIGNAL(installRemove()), + this, SLOT(installRemove())); + Q_ASSERT(ok); + + ok = connect(m_installManagerChooserObject, SIGNAL(refreshLists()), + this, SLOT(refreshLists())); + Q_ASSERT(ok); +} + +void InstallManager::setProperties() { + m_installManagerChooserObject->setProperty("sourceModel", QVariant::fromValue(&m_sourceModel)); + m_installManagerChooserObject->setProperty("categoryModel", QVariant::fromValue(&m_categoryModel)); + m_installManagerChooserObject->setProperty("languageModel", QVariant::fromValue(&m_languageModel)); + m_installManagerChooserObject->setProperty("worksModel", QVariant::fromValue(&m_worksModel)); + m_installManagerChooserObject->setProperty("sourceIndex", 0); + m_installManagerChooserObject->setProperty("visible", true); +} + +void InstallManager::sourceIndexChanged(int index) +{ + if (index < 0 || index >= m_sourceList.count()) + return; + + updateCategoryAndLanguageModels(); + updateWorksModel(); +} + +void InstallManager::categoryIndexChanged(int index) +{ + if (index < 0 || index >= m_categoryList.count()) + return; + updateWorksModel(); +} + +void InstallManager::languageIndexChanged(int index) +{ + if (index < 0 || index >= m_languageList.count()) + return; + updateWorksModel(); +} + +void InstallManager::workSelected(int index) { + QStandardItem* item = m_worksModel.item(index,0); + QVariant vInstalled = item->data(InstalledRole); + int installed = vInstalled.toInt(); + installed = installed == 0 ? 1 : 0; + item->setData(installed, InstalledRole); + + CSwordModuleInfo* moduleInfo = m_worksList.at(index); + m_modulesToInstallRemove[moduleInfo] = installed == 1; +} + +void InstallManager::cancel() { + m_installManagerChooserObject->setProperty("visible", false); +} + +void InstallManager::installRemove() { + m_installManagerChooserObject->setProperty("visible", false); + + QList<CSwordModuleInfo*> modulesToRemove; + QList<CSwordModuleInfo*> modulesToInstall; + QMap<CSwordModuleInfo*, bool>::const_iterator it; + for(it=m_modulesToInstallRemove.constBegin(); + it!=m_modulesToInstallRemove.constEnd(); + ++it) { + CSwordModuleInfo* moduleInfo = it.key(); + bool install = it.value(); + QString name = moduleInfo->name(); + if (moduleInstalled(*moduleInfo) && install == false) { + modulesToRemove.append(moduleInfo); + } + else if ( ! moduleInstalled(*moduleInfo) && install == true) { + modulesToInstall.append(moduleInfo); + } + } + removeModules(modulesToRemove); + installModules(modulesToInstall); +} + +void InstallManager::updateCategoryAndLanguageModels() +{ + QString sourceName = getCurrentListItem("sourceIndex", m_sourceList); + sword::InstallSource source = BtInstallBackend::source(sourceName); + CSwordBackend* backend = BtInstallBackend::backend(source); + const QList<CSwordModuleInfo*> modules = backend->moduleList(); + + QSet<QString> categories; + QSet<QString> languages; + for (int moduleIndex=0; moduleIndex<modules.count(); ++moduleIndex) { + CSwordModuleInfo* module = modules.at(moduleIndex); + CSwordModuleInfo::Category category = module->category(); + // QString name = module->name(); + QString categoryName = module->categoryName(category); + const CLanguageMgr::Language* language = module->language(); + QString languageName = language->englishName(); + categories.insert(categoryName); + languages.insert(languageName); + } + + QString currentCategory = getCurrentListItem("categoryIndex", m_categoryList); + m_categoryList = categories.toList(); + m_categoryList.sort(); + setupTextModel(m_categoryList, &m_categoryModel); + setCurrentListItem("categoryIndex", m_categoryList, currentCategory); + + QString currentLanguage = getCurrentListItem("languageIndex", m_languageList); + m_languageList = languages.toList(); + m_languageList.sort(); + setupTextModel(m_languageList, &m_languageModel); + setCurrentListItem("languageIndex", m_languageList, currentLanguage); +} + +QString InstallManager::getCurrentListItem(const char* propertyName, const QStringList& list) { + QString value; + QVariant vIndex = m_installManagerChooserObject->property(propertyName); + bool ok; + int index = vIndex.toInt(&ok); + if (ok) { + if (index >= 0 && index < list.count()) + value = list.at(index); + } + return value; +} + +void InstallManager::setCurrentListItem(const char* propertyName, + const QStringList& list, + const QString& itemName) { + int index = list.indexOf(itemName); + if (index < 0) + index = 0; + m_installManagerChooserObject->setProperty(propertyName, index); +} + +void InstallManager::updateWorksModel() +{ + QString sourceName = getCurrentListItem("sourceIndex", m_sourceList); + QString categoryName = getCurrentListItem("categoryIndex", m_categoryList); + QString languageName = getCurrentListItem("languageIndex", m_languageList); + + sword::InstallSource source = BtInstallBackend::source(sourceName); + CSwordBackend* backend = BtInstallBackend::backend(source); + const QList<CSwordModuleInfo*> modules = backend->moduleList(); + + m_worksTitleList.clear(); + m_worksDescList.clear(); + m_worksList.clear(); + m_worksInstalledList.clear(); + for (int moduleIndex=0; moduleIndex<modules.count(); ++moduleIndex) { + CSwordModuleInfo* module = modules.at(moduleIndex); + module->setProperty("installSourceName", sourceName); + CSwordModuleInfo::Category category = module->category(); + QString moduleCategoryName = module->categoryName(category); + const CLanguageMgr::Language* language = module->language(); + QString moduleLanguageName = language->englishName(); + if (moduleCategoryName == categoryName && + moduleLanguageName == languageName ) { + QString name = module->name(); + QString description = module->config(CSwordModuleInfo::Description); + QString version = module->config(CSwordModuleInfo::ModuleVersion); + QString info = description + ": " + version;\ + int installed = moduleInstalled(*module) ? 1 : 0; + m_worksTitleList.append(name); + m_worksDescList.append(info); + m_worksList.append(module); + m_worksInstalledList.append(installed); + } + } + setupWorksModel(m_worksTitleList, m_worksDescList, m_worksInstalledList, &m_worksModel); +} + +void InstallManager::removeModules(const QList<CSwordModuleInfo*>& modules) { + + QStringList moduleNames; + foreach ( CSwordModuleInfo* mInfo, modules ) { + QString moduleName = mInfo->name(); + moduleNames.append(moduleName); + } + // Update the module list before really removing. Remember deleting the pointers later. + QList<CSwordModuleInfo*> toBeDeleted = CSwordBackend::instance()->takeModulesFromList(moduleNames); + + sword::InstallMgr installMgr; + QMap<QString, sword::SWMgr*> mgrDict; //maps config paths to SWMgr objects + foreach ( CSwordModuleInfo* mInfo, toBeDeleted ) { + Q_ASSERT(mInfo); // Only installed modules could have been selected and returned by takeModulesFromList + // Find the install path for the sword manager + QString prefixPath = mInfo->config(CSwordModuleInfo::AbsoluteDataPath) + "/"; + QString dataPath = mInfo->config(CSwordModuleInfo::DataPath); + if (dataPath.left(2) == "./") { + dataPath = dataPath.mid(2); + } + if (prefixPath.contains(dataPath)) { //remove module part to get the prefix path + prefixPath = prefixPath.remove( prefixPath.indexOf(dataPath), dataPath.length() ); + } + else { //This is an error, should not happen + qWarning() << "Removing" << mInfo->name() << "didn't succeed because the absolute path" << prefixPath << "didn't contain the data path" << dataPath; + continue; // don't remove this, go to next of the for loop + } + + // Create the sword manager and remove the module + sword::SWMgr* mgr = mgrDict[ prefixPath ]; + if (!mgr) { //create new mgr if it's not yet available + mgrDict.insert(prefixPath, new sword::SWMgr(prefixPath.toLocal8Bit())); + mgr = mgrDict[ prefixPath ]; + } + qDebug() << "Removing the module" << mInfo->name() << "..."; + installMgr.removeModule(mgr, mInfo->module()->getName()); + } + //delete the removed moduleinfo pointers + qDeleteAll(modules); + //delete all mgrs which were created above + qDeleteAll(mgrDict); + mgrDict.clear(); +} + +void InstallManager::installModules(const QList<CSwordModuleInfo*>& modules) { + m_installProgress.openProgress(modules); +} + +void InstallManager::refreshLists() { + m_installSourcesManager.refreshSources(); +} + +} // end namespace diff --git a/src/mobile/bookshelfmanager/installmanager.h b/src/mobile/bookshelfmanager/installmanager.h new file mode 100644 index 0000000..a976ad8 --- /dev/null +++ b/src/mobile/bookshelfmanager/installmanager.h @@ -0,0 +1,82 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#ifndef INSTALL_MODULE_CHOOSER_H +#define INSTALL_MODULE_CHOOSER_H + +#include "installsourcesmanager.h" +#include "mobile/models/roleitemmodel.h" +#include "installprogress.h" +#include <QMap> +#include <QObject> + +class QQuickItem; +class CSwordModuleInfo; +class BtInstallMgr; + +namespace btm { + +class InstallManager :public QObject { + Q_OBJECT + +public: + InstallManager(QObject* parent = 0); + + Q_INVOKABLE void openChooser(); + +private slots: + void cancel(); + void categoryIndexChanged(int index); + void installRemove(); + void languageIndexChanged(int index); + void refreshLists(); + void sourceIndexChanged(int index); + void workSelected(int index); + +private: + QString getCurrentListItem(const char* propertyName, + const QStringList& list); + void findInstallManagerObject(); + void findProgressObject(); + void installModules(const QList<CSwordModuleInfo*>& modules); + void makeConnections(); + void removeModules(const QList<CSwordModuleInfo*>& modules); + void setProperties(); + void setupSourceModel(); + void setCurrentListItem(const char* propertyName, + const QStringList& list, + const QString& itemName); + void updateCategoryAndLanguageModels(); + void updateWorksModel(); + + QQuickItem* m_installManagerChooserObject; + QQuickItem* m_progressObject; + BtInstallMgr* m_btInstallMgr; + InstallSourcesManager m_installSourcesManager; + + InstallProgress m_installProgress; + QStringList m_sourceList; + QStringList m_categoryList; + QStringList m_languageList; + QStringList m_worksTitleList; + QStringList m_worksDescList; + QList<CSwordModuleInfo*> m_worksList; + QList<int> m_worksInstalledList; + QMap<CSwordModuleInfo*, bool> m_modulesToInstallRemove; + RoleItemModel m_sourceModel; + RoleItemModel m_categoryModel; + RoleItemModel m_languageModel; + RoleItemModel m_worksModel; +}; + +} // end namespace +#endif diff --git a/src/mobile/bookshelfmanager/installprogress.cpp b/src/mobile/bookshelfmanager/installprogress.cpp new file mode 100644 index 0000000..dd113ec --- /dev/null +++ b/src/mobile/bookshelfmanager/installprogress.cpp @@ -0,0 +1,199 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "installprogress.h" + +#include "backend/btinstallbackend.h" +#include "backend/managers/cswordbackend.h" +#include "backend/btinstallthread.h" +#include "mobile/btmmain.h" +#include "mobile/ui/qtquick2applicationviewer.h" +#include "mobile/ui/viewmanager.h" +#include <QQuickItem> +#include <QDebug> + +namespace btm { + +InstallProgress::InstallProgress(QObject* parent) + : QObject(parent), m_progressObject(0) { +} + +void InstallProgress::openProgress(const QList<CSwordModuleInfo*>& modules) { + if (modules.count() == 0) + return; + + if (m_progressObject == 0) + findProgressObject(); + if (m_progressObject == 0) + return; + + QString destination = getSourcePath(); + if (destination.isEmpty()) + return; + + setProperties(); + + Q_FOREACH(const CSwordModuleInfo *module, modules) { + const QString sourceName(module->property("installSourceName").toString()); + // create a thread for this module + BtInstallThread* thread = new BtInstallThread(module->name(), sourceName, destination); + m_waitingThreads.insert(sourceName, thread); + m_threadsByModule.insert(module->name(), thread); + + QObject::connect(thread, SIGNAL(installStopped(QString, QString)), + this, SLOT(slotOneItemStopped(QString, QString)), Qt::QueuedConnection); + QObject::connect(thread, SIGNAL(installCompleted(QString, QString, int)), + this, SLOT(slotOneItemCompleted(QString, QString, int)), Qt::QueuedConnection); + QObject::connect(thread, SIGNAL(statusUpdated(QString, int)), + this, SLOT(slotStatusUpdated(QString, int)), Qt::QueuedConnection); + QObject::connect(thread, SIGNAL(downloadStarted(QString)), + this, SLOT(slotDownloadStarted(QString)), Qt::QueuedConnection); + QObject::connect(thread, SIGNAL(preparingInstall(QString, QString)), + this, SLOT(slotInstallStarted(QString, QString)), Qt::QueuedConnection); + } + + connect(m_progressObject, SIGNAL(cancel()), this, SLOT(slotStopInstall())); + startThreads(); +} + +void InstallProgress::cancel() { + m_progressObject->setProperty("visible", false); +} + +void InstallProgress::close() { + m_progressObject->setProperty("visible", false); + CSwordBackend::instance()->reloadModules(CSwordBackend::AddedModules); +} + +void InstallProgress::slotOneItemCompleted(QString module, QString source, int status) { + QString message; + //status comes from the sword installer. + if (status != 0) { + message = tr("Failed"); + } + else { + message = tr("Completed"); + } + oneItemStoppedOrCompleted(module, source, message); +} + +void InstallProgress::slotOneItemStopped(QString module, QString source) { + oneItemStoppedOrCompleted(module, source, tr("Cancelled")); +} + +// TODO show failed status +void InstallProgress::oneItemStoppedOrCompleted(QString module, QString source, QString statusMessage) { + qDebug() << "\n**********************************\nBtInstallProgressDialog::oneItemStoppedOrCompleted" << module << statusMessage << "\n******************************************"; + qDebug() << "remove from threads maps" << source << m_threadsByModule.value(module); + m_runningThreads.remove(source, m_threadsByModule.value(module)); + m_waitingThreads.remove(source, m_threadsByModule.value(module)); + + //non-concurrent + QMultiMap<QString, BtInstallThread*>::iterator threadIterator = m_waitingThreads.end(); + if (m_runningThreads.isEmpty() && threadIterator != m_waitingThreads.begin()) { + --threadIterator; // the last item + QString sourceName = threadIterator.key(); + BtInstallThread* t = threadIterator.value(); + m_runningThreads.insert(sourceName, t); + threadIterator = m_waitingThreads.erase(threadIterator); + t->start(); + } + + if (threadsDone()) { + qDebug() << "close the dialog"; + close(); + } +} + +void InstallProgress::slotStopInstall() { + qDebug() << "BtInstallProgressDialog::slotStopInstall"; + + // Clear the waiting threads map, stop all running threads. + m_waitingThreads.clear(); + if (m_runningThreads.count() > 0) { + foreach(BtInstallThread* thread, m_runningThreads) { + thread->slotStopInstall(); + } + } + else { + close(); + } +} + +void InstallProgress::slotStatusUpdated(QString /* module */, int status) { + m_progressObject->setProperty("value", status); +} + +void InstallProgress::slotInstallStarted(QString /* module */, QString) { +} + +void InstallProgress::slotDownloadStarted(QString module) { + QString message = "Installing " + module; + m_progressObject->setProperty("text", message); + m_progressObject->setProperty("value", 0); +} + +void InstallProgress::startThreads() { + QMultiMap<QString, BtInstallThread*>::iterator threadIterator = m_waitingThreads.end(); + if (threadIterator != m_waitingThreads.begin()) { + // go to the last item which is actually the first in the visible list + // because the iterator is reversed compared to insert order + --threadIterator; + QString sourceName = threadIterator.key(); + BtInstallThread* t = threadIterator.value(); + m_runningThreads.insert(sourceName, t); + threadIterator = m_waitingThreads.erase(threadIterator); + t->start(); + } +} + +bool InstallProgress::threadsDone() { + return (m_waitingThreads.isEmpty() && m_runningThreads.isEmpty()); +} + +void InstallProgress::findProgressObject() { + QtQuick2ApplicationViewer* viewer = getViewManager()->getViewer(); + QQuickItem * rootObject = 0; + if (viewer != 0) + rootObject = viewer->rootObject(); + if (rootObject != 0) + m_progressObject = rootObject->findChild<QQuickItem*>("progress"); +} + +void InstallProgress::setProperties() { + m_progressObject->setProperty("visible", true); + m_progressObject->setProperty("minimumValue", 0.0); + m_progressObject->setProperty("maximumValue", 100.0); + m_progressObject->setProperty("value", 0.0); +} + +QString InstallProgress::getSourcePath() { + QStringList targets = BtInstallBackend::targetList(); + for (QStringList::iterator it = targets.begin(); it != targets.end(); ++it) { + // Add the path only if it's writable + QString sourcePath = *it; + if (sourcePath.isEmpty()) + continue; + QDir dir(sourcePath); + if (!dir.exists()) + continue; + if (!dir.isReadable()) + continue; + QFileInfo fi( dir.canonicalPath()); + if (!fi.isWritable()) + continue; + return sourcePath; + } + return QString(); +} + +} diff --git a/src/mobile/bookshelfmanager/installprogress.h b/src/mobile/bookshelfmanager/installprogress.h new file mode 100644 index 0000000..4f9908c --- /dev/null +++ b/src/mobile/bookshelfmanager/installprogress.h @@ -0,0 +1,61 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#ifndef INSTALL_PROGRESS_H +#define INSTALL_PROGRESS_H + +#include <QObject> +#include <QMultiMap> +#include <QMap> + +class QQuickItem; +class CSwordModuleInfo; +class BtInstallThread; + +namespace btm { + +class InstallProgress: public QObject { + Q_OBJECT + +public: + InstallProgress(QObject* parent = 0); + + void openProgress(const QList<CSwordModuleInfo*>& modules); + +private slots: + void cancel(); + void close(); + void slotOneItemCompleted(QString module, QString source, int status); + void slotOneItemStopped(QString module, QString source); + void slotStopInstall(); + void slotStatusUpdated(QString module, int status); + void slotDownloadStarted(QString module); + void slotInstallStarted(QString module, QString); + bool threadsDone(); + +private: + void findProgressObject(); + QString getSourcePath(); + void oneItemStoppedOrCompleted(QString module, QString source, QString message); + void setProperties(); + void startThreads(); + + QQuickItem* m_progressObject; + QMultiMap<QString, BtInstallThread*> m_waitingThreads; + QMultiMap<QString, BtInstallThread*> m_runningThreads; + QMap<QString, BtInstallThread*> m_threadsByModule; +}; + + +} + +#endif diff --git a/src/mobile/bookshelfmanager/installsources.cpp b/src/mobile/bookshelfmanager/installsources.cpp new file mode 100644 index 0000000..6f6fa91 --- /dev/null +++ b/src/mobile/bookshelfmanager/installsources.cpp @@ -0,0 +1,75 @@ +/********* +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#include "installsources.h" + +#include "backend/btinstallbackend.h" +#include "backend/btinstallmgr.h" +#include <QDebug> + +namespace btm { + +InstallSources::InstallSources(QObject *parent) + : QObject(parent), + done(false), + m_cancelled(false) { + m_iMgr = new BtInstallMgr(); +} + + +InstallSources::~InstallSources() { + delete m_iMgr; +} + +void InstallSources::process() { + + m_canceled = false; + refreshSourceList(); + if (m_canceled) + return; + QStringList sourceNames = BtInstallBackend::sourceNameList(); + refreshWorks(sourceNames); + emit finished(); +} + +void InstallSources::refreshSourceList() { + int ret = m_iMgr->refreshRemoteSourceConfiguration(); + if (ret ) { + qWarning("InstallMgr: getting remote list returned an error."); + } +} + +void InstallSources::refreshWorks(const QStringList& sourceNames) { + int sourceCount = sourceNames.count(); + for (int i=0; i<sourceCount; ++i) { + if (m_canceled) + break; + QString sourceName = sourceNames.at(i); + int percent = 10 + 90 *((double)i/sourceCount); + QString title = "Refreshing " + sourceName; + emit percentComplete(percent, title); + qDebug() << title << percent; + sword::InstallSource source = BtInstallBackend::source(sourceName); + bool result = (m_iMgr->refreshRemoteSource(&source) == 0); + if (result) { + ; + } else { + QString error = QString(tr("Failed to refresh source %1")).arg(sourceName); + qDebug() << error; + } + } + emit percentComplete(100, "Done"); +} + +void InstallSources::cancel() { + m_canceled = true; + qDebug() << "IS canceled"; +} + +} diff --git a/src/mobile/bookshelfmanager/installsources.h b/src/mobile/bookshelfmanager/installsources.h new file mode 100644 index 0000000..f552c68 --- /dev/null +++ b/src/mobile/bookshelfmanager/installsources.h @@ -0,0 +1,52 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#ifndef INSTALLSOURCESTHREAD_H +#define INSTALLSOURCESTHREAD_H + +#include <QObject> + +class BtInstallMgr; + +namespace btm { + +class InstallSources : public QObject { + Q_OBJECT + public: + InstallSources(QObject *parent = 0); + + ~InstallSources(); + + public slots: + void process(); + void cancel(); + + public: + bool done; + + protected: + void refreshSourceList(); + void refreshWorks(const QStringList& sourceNames); + + bool m_cancelled; + BtInstallMgr* m_iMgr; + + signals: + void finished(); + void error(QString err); + void percentComplete(int percent, const QString& title); + +private: + bool m_canceled; +}; + +} +#endif diff --git a/src/mobile/bookshelfmanager/installsourcesmanager.cpp b/src/mobile/bookshelfmanager/installsourcesmanager.cpp new file mode 100644 index 0000000..bc55f12 --- /dev/null +++ b/src/mobile/bookshelfmanager/installsourcesmanager.cpp @@ -0,0 +1,85 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "installsourcesmanager.h" + +#include "installsources.h" +#include "backend/btinstallbackend.h" +#include "mobile/btmmain.h" +#include "mobile/ui/qtquick2applicationviewer.h" +#include "mobile/ui/viewmanager.h" +#include <QDebug> +#include <QQuickItem> +#include <QThread> + +namespace btm { + +InstallSourcesManager::InstallSourcesManager(QObject* /* parent */) + : m_worker(0) { +} + +InstallSourcesManager::~InstallSourcesManager() { +} + +void InstallSourcesManager::refreshSources() { + findProgressObject(); + Q_ASSERT(m_progressObject != 0); + if (m_progressObject == 0) + return; + m_progressObject->disconnect(this); + connect(m_progressObject, SIGNAL(cancel()), this, SLOT(cancel())); + + m_progressObject->setProperty("minimumValue", 0.0); + m_progressObject->setProperty("maximumValue", 100.0); + m_progressObject->setProperty("value", 0.0); + m_progressObject->setProperty("visible", true); + m_progressObject->setProperty("text", "Refreshing Source List"); + + runThread(); +} + +void InstallSourcesManager::cancel() { + m_worker->cancel(); + m_progressObject->setProperty("visible", false); +} + +void InstallSourcesManager::runThread() { + QThread* thread = new QThread; + m_worker = new InstallSources(); + m_worker->moveToThread(thread); +// connect(m_worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); + connect(thread, SIGNAL(started()), m_worker, SLOT(process())); + connect(m_worker, SIGNAL(finished()), thread, SLOT(quit())); + connect(m_worker, SIGNAL(finished()), m_worker, SLOT(deleteLater())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + connect(m_worker, SIGNAL(percentComplete(int, const QString&)), + this, SLOT(percentComplete(int, const QString&))); + thread->start(); +} + +void InstallSourcesManager::percentComplete(int percent, const QString& title) { + m_progressObject->setProperty("value", percent); + m_progressObject->setProperty("text", title); + if (percent == 100) + m_progressObject->setProperty("visible", false); +} + +void InstallSourcesManager::findProgressObject() { + QtQuick2ApplicationViewer* viewer = getViewManager()->getViewer(); + QQuickItem * rootObject = 0; + if (viewer != 0) + rootObject = viewer->rootObject(); + if (rootObject != 0) + m_progressObject = rootObject->findChild<QQuickItem*>("progress"); +} + +} // end namespace diff --git a/src/mobile/bookshelfmanager/installsourcesmanager.h b/src/mobile/bookshelfmanager/installsourcesmanager.h new file mode 100644 index 0000000..07665b4 --- /dev/null +++ b/src/mobile/bookshelfmanager/installsourcesmanager.h @@ -0,0 +1,45 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#ifndef INSTALL_SOURCES_MANAGER_H +#define INSTALL_SOURCES_MANAGER_H + +#include <QObject> +#include <QQuickItem> + +namespace btm { + +class InstallSources; + +class InstallSourcesManager :public QObject { + Q_OBJECT + +public: + InstallSourcesManager(QObject* parent = 0); + ~InstallSourcesManager(); + + void refreshSources(); + +private slots: + void cancel(); + void percentComplete(int percent, const QString& title); + +private: + void findProgressObject(); + void runThread(); + + QQuickItem* m_progressObject; + InstallSources* m_worker; +}; + +} // end namespace +#endif diff --git a/src/mobile/btmmain.cpp b/src/mobile/btmmain.cpp new file mode 100644 index 0000000..12cbbf4 --- /dev/null +++ b/src/mobile/btmmain.cpp @@ -0,0 +1,106 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "bibletime.h" +#include "backend/config/btconfig.h" +#include "backend/bookshelfmodel/btbookshelftreemodel.h" +#include "mobile/bibletimeapp.h" +#include "mobile/bookshelfmanager/installmanager.h" +#include "mobile/ui/btstyle.h" +#include "mobile/ui/btwindowinterface.h" +#include "mobile/ui/moduleinterface.h" +#include "mobile/ui/qtquick2applicationviewer.h" +#include "mobile/ui/viewmanager.h" +#include <QBrush> +#include <QColor> +#include <QGuiApplication> +#include <QPalette> +#include <QQuickItem> +#include <QQmlDebuggingEnabler> +#include <QMetaType> +#include <QTranslator> +#include "util/directory.h" + +btm::ViewManager* mgr = 0; + +void register_gml_classes() { + QQmlDebuggingEnabler enabler; + + qmlRegisterType<btm::BtWindowInterface>("BibleTime", 1, 0, "BtWindowInterface"); + qmlRegisterType<btm::BtStyle>("BibleTime", 1, 0, "BtStyle"); + qmlRegisterType<btm::InstallManager>("BibleTime", 1, 0, "InstallManager"); + qmlRegisterType<btm::ModuleInterface>("BibleTime", 1, 0, "ModuleInterface"); +} + +btm::ViewManager* getViewManager() { + return mgr; +} + +/******************************************************************************* + Handle Qt's meta type system. +*******************************************************************************/ + +void registerMetaTypes() { + qRegisterMetaType<FilterOptions>("FilterOptions"); + qRegisterMetaType<DisplayOptions>("DisplayOptions"); + qRegisterMetaTypeStreamOperators<BtBookshelfTreeModel::Grouping>("BtBookshelfTreeModel::Grouping"); + + qRegisterMetaType<BTModuleTreeItem::Grouping>("Grouping"); + qRegisterMetaTypeStreamOperators<BTModuleTreeItem::Grouping>("Grouping"); + + qRegisterMetaType<BtConfig::StringMap>("StringMap"); + qRegisterMetaTypeStreamOperators<BtConfig::StringMap>("StringMap"); + + qRegisterMetaType<QList<int> >("QList<int>"); + qRegisterMetaTypeStreamOperators<QList<int> >("QList<int>"); +} + + +int main(int argc, char *argv[]) { + namespace DU = util::directory; + + BibleTimeApp app(argc, argv); //for QApplication + + registerMetaTypes(); + + if (!DU::initDirectoryCache()) { + qFatal("Error initializing directory cache!"); + return EXIT_FAILURE; + } + + app.startInit(); + if (!app.initBtConfig()) { + return EXIT_FAILURE; + } + + //first install QT's own translations + QTranslator qtTranslator; + qtTranslator.load("qt_" + QLocale::system().name()); + app.installTranslator(&qtTranslator); + //then our own + QTranslator BibleTimeTranslator; + BibleTimeTranslator.load( QString("bibletime_ui_").append(QLocale::system().name()), DU::getLocaleDir().canonicalPath()); + app.installTranslator(&BibleTimeTranslator); + +// // a new BibleTime version was installed (maybe a completely new installation) +// if (btConfig().value<QString>("bibletimeVersion", BT_VERSION) != BT_VERSION) { +// btConfig().setValue("bibletimeVersion", QString(BT_VERSION)); +// mainWindow->saveConfigSettings(); +// } + + register_gml_classes(); + mgr = new btm::ViewManager; + mgr->show(); + btm::BibleTime btm; + + return app.exec(); +} diff --git a/src/mobile/btmmain.h b/src/mobile/btmmain.h new file mode 100644 index 0000000..64bd25e --- /dev/null +++ b/src/mobile/btmmain.h @@ -0,0 +1,23 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#ifndef VIEW_MANAGER_INCLUDED +#define VIEW_MANAGER_INCLUDED + +namespace btm { + class ViewManager; +} + +btm::ViewManager* getViewManager(); + +#endif + diff --git a/src/mobile/keychooser/bookkeychooser.cpp b/src/mobile/keychooser/bookkeychooser.cpp new file mode 100644 index 0000000..9ae3ef9 --- /dev/null +++ b/src/mobile/keychooser/bookkeychooser.cpp @@ -0,0 +1,272 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "bookkeychooser.h" + +#include <cmath> +#include "mobile/ui/btwindowinterface.h" +#include "mobile/ui/qtquick2applicationviewer.h" +#include <QCoreApplication> +#include <QDebug> +#include <QQmlProperty> +#include <QQmlContext> +#include <QQmlProperty> +#include <QQuickItem> +#include <QStandardItem> +#include <QString> + +namespace btm { + +struct BookEntry { + enum BookRoles { + NameRole = Qt::UserRole + 1, + ChildCountRole + }; +}; + +BookKeyChooser::BookKeyChooser(QtQuick2ApplicationViewer* viewer, + BtWindowInterface* windowInterface) + : m_viewer(viewer), + m_windowInterface(windowInterface), + m_key(0), + m_treeChooserObject(0), + m_state(CLOSED ) { + findTreeChooserObject(); + initializeRoleNameModel(); +} + +void BookKeyChooser::copyKey() +{ + CSwordKey* key = m_windowInterface->getKey(); + CSwordTreeKey* bookKey = dynamic_cast<CSwordTreeKey*>(key); + m_key = new CSwordTreeKey(*bookKey); +} + +void BookKeyChooser::findTreeChooserObject() { + QQuickItem * rootObject = m_viewer->rootObject(); + if (rootObject != 0) + m_treeChooserObject = rootObject->findChild<QQuickItem*>("treeChooser"); +} + +void BookKeyChooser::initializeRoleNameModel() { + QHash<int, QByteArray> roleNames; + roleNames[BookEntry::NameRole] = "name"; + roleNames[BookEntry::ChildCountRole] = "childcount"; + m_roleItemModel.setRoleNames(roleNames); +} + +void BookKeyChooser::populateRoleNameModel(const QStringList& sibblings, const QList<int>& sibblingChildCounts) { + m_roleItemModel.clear(); + Q_ASSERT(sibblings.count() == sibblingChildCounts.count()); + for (int i=0; i< sibblings.count(); ++i) { + QString sibbling = sibblings.at(i); + int childCount = sibblingChildCounts.at(i); + QStandardItem* item = new QStandardItem(); + item->setData(sibbling, BookEntry::NameRole); + item->setData(childCount, BookEntry::ChildCountRole); + m_roleItemModel.appendRow(item); + } +} + +static QString constructPath(const QStringList& pathList) { + QString path; + for (int i=0; i< pathList.count(); ++i) { + QString leaf = QString("/") + pathList.at(i); + path.append(leaf); + } + return path; +} + +static QString getBackPath(const CSwordTreeKey& key) { + QString path = key.key(); + QStringList pathList = path.split('/', QString::SkipEmptyParts); + pathList.removeLast(); + + QString backPath; + if (pathList.count() == 0) + return backPath; + + backPath = constructPath(pathList); + return backPath; +} + +void BookKeyChooser::select(QString value) { + openChooser(false); + + QStringList keyPathList = getKeyPath(); + keyPathList.removeLast(); + keyPathList.append(value); + QString newPath = constructPath(keyPathList); + CSwordTreeKey* tmpBookKey = dynamic_cast<CSwordTreeKey*>(m_key); + tmpBookKey->setKey(newPath); + + CSwordKey* key = m_windowInterface->getKey(); + CSwordTreeKey* bookKey = dynamic_cast<CSwordTreeKey*>(key); + bookKey->setKey(*tmpBookKey); + + emit referenceChanged(); +} + +void BookKeyChooser::open() { + copyKey(); + + CSwordTreeKey tmpKey(*m_key); + m_backPath = getBackPath(tmpKey); + QStringList siblings; + QList<int> hasChildrenList; + parseKey(&siblings, &hasChildrenList, &tmpKey); + populateRoleNameModel(siblings, hasChildrenList); + openChooser(true); +} + +void BookKeyChooser::next(QString value) { + openChooser(false); + + QStringList keyPathList = getKeyPath(); + keyPathList.removeLast(); + keyPathList.append(value); + + QString newPath = constructPath(keyPathList); + m_key->setKey(newPath); + m_key->firstChild(); + + CSwordTreeKey tmpKey(*m_key); + m_backPath = getBackPath(tmpKey); + QStringList siblings; + QList<int> counts; + parseKey(&siblings, &counts, &tmpKey); + populateRoleNameModel(siblings, counts); + openChooser(true); + + m_key->setKey(tmpKey); +} + +void BookKeyChooser::back() { + openChooser(false); + + QStringList keyPathList = getKeyPath(); + keyPathList.removeLast(); + + QString newPath = constructPath(keyPathList); + keyPathList.removeLast(); + m_key->setKey(newPath); + + CSwordTreeKey tmpKey(*m_key); + m_backPath = getBackPath(tmpKey); + QStringList siblings; + QList<int> counts; + parseKey(&siblings, &counts, &tmpKey); + populateRoleNameModel(siblings, counts); + + openChooser(true); +} + +void BookKeyChooser::stringCanceled() { +} + +void BookKeyChooser::setProperties() { + m_treeChooserObject->setProperty("path",m_backPath); + m_treeChooserObject->setProperty("model", QVariant::fromValue(&m_roleItemModel)); +} + +void BookKeyChooser::openChooser(bool open) { + Q_ASSERT(m_treeChooserObject != 0); + if (m_treeChooserObject == 0) + return; + + m_treeChooserObject->disconnect(); + bool ok = connect(m_treeChooserObject, SIGNAL(select(QString)), + this, SLOT(select(QString))); + Q_ASSERT(ok); + + ok = connect(m_treeChooserObject, SIGNAL(next(QString)), + this, SLOT(next(QString))); + Q_ASSERT(ok); + + ok = connect(m_treeChooserObject, SIGNAL(back()), + this, SLOT(back())); + Q_ASSERT(ok); + + setProperties(); + + m_treeChooserObject->setProperty("visible",open); +} + +QStringList BookKeyChooser::getKeyPath() const { + QString oldKey = m_key->key(); //string backup of key + + if (oldKey.isEmpty()) { //don't set keys equal to "/", always use a key which may have content + m_key->firstChild(); + oldKey = m_key->key(); + } + + QStringList siblings; //split up key + if (!oldKey.isEmpty()) { + siblings = oldKey.split('/', QString::SkipEmptyParts); + } + return siblings; +} + +static int findEntry(const QString& sibling, bool* found, + CSwordTreeKey* key, QString* matchingKey, QStringList* siblings, QList<int>* hasChildrenList) { + int index = 0; + int foundIndex = 0; + do { //look for matching sibling + QString keyName = key->getLocalNameUnicode(); + if (keyName == sibling) { + *found = true; + foundIndex = index; + *matchingKey = key->key(); + } + siblings->append(keyName); + bool hasChildren = key->hasChildren(); + hasChildrenList->append(hasChildren ? 1 : 0); + ++index; + } while (key->nextSibling()); + return foundIndex; +} + +void BookKeyChooser::parseKey(QStringList * siblings, + QList<int>* hasChildrenList, CSwordTreeKey* key) { + QString oldKey = key->key(); + QStringList pathDepthList = oldKey.split("/", QString::SkipEmptyParts); + int depth = 0; + key->root(); + + while ( key->firstChild() && (depth < pathDepthList.count()) ) { + QString localName = key->getLocalNameUnicode(); + QString savedKey = key->key(); + bool found = false; + QString path = pathDepthList[depth]; + siblings->clear(); + hasChildrenList->clear(); + QString matchingKey; + findEntry(path, &found, key, &matchingKey, siblings, hasChildrenList); + if (found) { + key->setKey(matchingKey); + } + depth++; + } +} + +void BookKeyChooser::createModel() +{ + m_model.clear(); + + QStandardItem *parentItem = m_model.invisibleRootItem(); + for (int i = 0; i < 4; ++i) { + QStandardItem *item = new QStandardItem("item1"); + parentItem->appendRow(item); + } +} + +} // end namespace diff --git a/src/mobile/keychooser/bookkeychooser.h b/src/mobile/keychooser/bookkeychooser.h new file mode 100644 index 0000000..720e5f0 --- /dev/null +++ b/src/mobile/keychooser/bookkeychooser.h @@ -0,0 +1,81 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#ifndef BOOK_KEY_CHOOSER_H +#define BOOK_KEY_CHOOSER_H + +#include "backend/keys/cswordtreekey.h" +#include <QObject> +#include <QList> +#include <QStringList> +#include <QStandardItemModel> +#include "mobile/models/roleitemmodel.h" + +class QtQuick2ApplicationViewer; +class QQmlComponent; +class QQuickItem; + +namespace btm { + +class BtWindowInterface; + +class BookKeyChooser : public QObject { + Q_OBJECT + + enum State { + CLOSED, + BOOK, + CHAPTER, + VERSE + }; + +public: + BookKeyChooser(QtQuick2ApplicationViewer* viewer, BtWindowInterface* windowInterface); + void open(); + +signals: + void referenceChanged(); + +private slots: + void select(QString value); + void next(QString value); + void back(); + void stringCanceled(); + +private: + void copyKey(); + void findTreeChooserObject(); + QStringList getKeyPath() const; + void showGridChooser(const QStringList& list); + void setProperties(const QStringList& list); + void parseKey(QStringList * sibblings, QList<int>* hasChildrenList, CSwordTreeKey* key); + void createModel(); + void setProperties(); + void initializeRoleNameModel(); + void populateRoleNameModel(const QStringList& sibblings, const QList<int>& sibblingChildCounts); + void openChooser(bool open); + + + QtQuick2ApplicationViewer* m_viewer; + BtWindowInterface* m_windowInterface; + CSwordTreeKey* m_key; + QQuickItem* m_treeChooserObject; + int m_state; + QString m_backPath; + QStringList m_sibblings; + QStandardItemModel m_model; + RoleItemModel m_roleItemModel; +}; + +} // end namespace + +#endif diff --git a/src/mobile/keychooser/versechooser.cpp b/src/mobile/keychooser/versechooser.cpp new file mode 100644 index 0000000..f510da0 --- /dev/null +++ b/src/mobile/keychooser/versechooser.cpp @@ -0,0 +1,160 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "versechooser.h" + +#include "backend/keys/cswordversekey.h" +#include "backend/drivers/cswordbiblemoduleinfo.h" +#include "backend/drivers/cswordmoduleinfo.h" +#include <cmath> +#include "mobile/ui/btwindowinterface.h" +#include "mobile/ui/gridchooser.h" +#include "mobile/ui/qtquick2applicationviewer.h" +#include <QQuickItem> +#include <QQmlProperty> +#include <QQmlContext> +#include <QDebug> +#include <QQmlProperty> +#include <QCoreApplication> + +namespace btm { + +VerseChooser::VerseChooser(QtQuick2ApplicationViewer* viewer, BtWindowInterface* bibleVerse) + : m_viewer(viewer), + m_gridChooser(0), + bibleVerse_(bibleVerse), + m_key(0), + m_state(CLOSED ) { + m_gridChooser = new GridChooser(m_viewer); + bool ok = connect(m_gridChooser, SIGNAL(accepted(const QString&)), + this, SLOT(stringAccepted(const QString&))); + Q_ASSERT(ok); +} + +void VerseChooser::open(CSwordVerseKey* key) { + if (key == 0) + return; + m_key = key; + m_oldBook = getBook(); + m_oldChapter = getChapter(); + m_oldVerse = getVerse(); + m_state = BOOK; + QStringList books = getBooks(); + m_gridChooser->open(books, m_oldBook, "Book"); +} + +void VerseChooser::stringAccepted(const QString& value) { + if (m_state == BOOK) { + m_newBook = value; + m_state = CHAPTER; + setBook(value); + QStringList chapters = getChapters(); + m_gridChooser->open(chapters, m_oldChapter, "Chapter"); + } + else if (m_state == CHAPTER) { + m_newChapter = value; + m_state = VERSE; + setChapter(value); + QStringList verses = getVerses(); + m_gridChooser->open(verses, m_oldVerse, "Verse"); + } + else if (m_state == VERSE) { + m_newVerse = value; + m_state = CLOSED; + setVerse(m_newVerse); + } +} + +void VerseChooser::stringCanceled() { +} + +QString VerseChooser::getBook() const { + QString book; + if (m_key) + book = m_key->book(); + return book; +} + +void VerseChooser::setBook(const QString& book) { + if (m_key) { + m_key->book(book); + } +} + +QString VerseChooser::getChapter() const { + QString chapter; + if (m_key) + chapter = QString::number(m_key->getChapter()); + return chapter; +} + +void VerseChooser::setChapter(const QString& chapter) { + if (m_key) { + int iChapter = chapter.toInt(); + m_key->setChapter(iChapter); + } +} + +QString VerseChooser::getVerse() const { + QString verse; + if (m_key) { + verse = QString::number(m_key->getVerse()); + } + return verse; +} + +void VerseChooser::setVerse(const QString& verse) { + if (m_key) { + int iVerse = verse.toInt(); + m_key->setVerse(iVerse); + emit referenceChanged(); + } +} + +QStringList VerseChooser::getBooks() const { + QStringList books; + const CSwordModuleInfo* module = m_key->module(); + const CSwordBibleModuleInfo* bibleModule = qobject_cast<const CSwordBibleModuleInfo*>(module); + if (bibleModule) + books = *bibleModule->books(); + return books; +} + +QStringList VerseChooser::getChapters() const { + QStringList chapters; + const CSwordModuleInfo* module = m_key->module(); + const CSwordBibleModuleInfo* m = qobject_cast<const CSwordBibleModuleInfo*>(module); + + QString book = m_key->book(); + int count = m->chapterCount(book); + for (int i = 1; i <= count; i++) { + chapters << QString::number(i); + } + return chapters; +} + +QStringList VerseChooser::getVerses() const { + QStringList verses; + const CSwordModuleInfo* module = m_key->module(); + const CSwordBibleModuleInfo* m = qobject_cast<const CSwordBibleModuleInfo*>(module); + QString book = m_key->book(); + int chapter = m_key->getChapter(); + int count = m->verseCount(book,chapter); + for (int i = 1; i <= count; i++) { + verses << QString::number(i); + } + return verses; +} + + + +} // end namespace diff --git a/src/mobile/keychooser/versechooser.h b/src/mobile/keychooser/versechooser.h new file mode 100644 index 0000000..3c7f52b --- /dev/null +++ b/src/mobile/keychooser/versechooser.h @@ -0,0 +1,86 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#ifndef VERSE_CHOOSER_H +#define VERSE_CHOOSER_H + +#include <QObject> +#include <QList> + +class CSwordVerseKey; +class QtQuick2ApplicationViewer; +class QQmlComponent; +class QQuickItem; +class QStringList; + +namespace btm { + +class GridChooser; + +class BtWindowInterface; + +class VerseChooser : public QObject { + Q_OBJECT + + enum State { + CLOSED, + BOOK, + CHAPTER, + VERSE + }; + +public: + VerseChooser(QtQuick2ApplicationViewer* viewer, BtWindowInterface* bibleVerse); + void open(CSwordVerseKey* key); + +signals: + void referenceChanged(); + +private slots: + void stringAccepted(const QString& value); + void stringCanceled(); + +private: + QString getBook() const; + void setBook(const QString& book); + + QString getChapter() const; + void setChapter(const QString& chapter); + + QString getVerse() const; + void setVerse(const QString& chapter); + + QStringList getBooks() const; + QStringList getChapters() const; + QStringList getVerses() const; + + void showGridChooser(const QStringList& list); + void setProperties(const QStringList& list); + + + QtQuick2ApplicationViewer* m_viewer; + GridChooser* m_gridChooser; + BtWindowInterface* bibleVerse_; + CSwordVerseKey* m_key; + int m_state; + + QString m_oldBook; + QString m_oldChapter; + QString m_oldVerse; + QString m_newBook; + QString m_newChapter; + QString m_newVerse; +}; + +} // end namespace + +#endif diff --git a/src/mobile/models/bibletextmodelbuilder.cpp b/src/mobile/models/bibletextmodelbuilder.cpp new file mode 100644 index 0000000..20faf14 --- /dev/null +++ b/src/mobile/models/bibletextmodelbuilder.cpp @@ -0,0 +1,184 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "bibletextmodelbuilder.h" + +#include "btglobal.h" +#include "backend/keys/cswordversekey.h" +#include "backend/drivers/cswordbiblemoduleinfo.h" +#include "backend/managers/cswordbackend.h" + +namespace btm { + +struct BookEntry { + enum TextRoles { + ReferenceRole = Qt::UserRole + 1, + TextRole = Qt::UserRole + 2 + }; +}; + +BibleTextModelBuilder::BibleTextModelBuilder(RoleItemModel* model) + : m_model(model) { + QHash<int, QByteArray> roleNames; + roleNames[BookEntry::ReferenceRole] = "ref"; + roleNames[BookEntry::TextRole] = "line"; + m_model->setRoleNames(roleNames); +} + +void BibleTextModelBuilder::updateModel( + QList<const CSwordModuleInfo*> modules, + const QString& keyName) { + + Q_ASSERT( modules.count() >= 1 ); + Q_ASSERT( !keyName.isEmpty() ); + + FilterOptions options; + options.footnotes = 0; + options.strongNumbers = 0; + options.headings = 1; + options.morphTags = 0; + options.lemmas = 0; + options.hebrewPoints = 0; + options.greekAccents = 0; + options.textualVariants = 0; + options.redLetterWords = 1; + options.scriptureReferences = 0; + options.morphSegmentation = 0; + CSwordBackend::instance()->setFilterOptions(options); + + const CSwordModuleInfo *module = modules.first(); + + if (modules.count() == 1) + module->module()->setSkipConsecutiveLinks( true ); //skip empty, linked verses + + QString startKey = keyName; + QString endKey = startKey; + + //check whether there's an intro we have to include + Q_ASSERT((module->type() == CSwordModuleInfo::Bible)); + + if (module->type() == CSwordModuleInfo::Bible) { + ((sword::VerseKey*)(module->module()->getKey()))->setIntros(true); + + Q_ASSERT(dynamic_cast<const CSwordBibleModuleInfo*>(module) != 0); + const CSwordBibleModuleInfo* bible = + static_cast<const CSwordBibleModuleInfo*>(module); + + CSwordVerseKey k1(module); + k1.setIntros(true); + k1.setKey(keyName); + + if (k1.getChapter() == 1) + k1.setChapter(0); // Chapter 1, start with 0:0, otherwise X:0 + + k1.setVerse(0); + + startKey = k1.key(); + + if (k1.getChapter() == 0) + k1.setChapter(1); + + k1.setVerse(bible->verseCount(k1.book(), k1.getChapter())); + endKey = k1.key(); + } + + updateKeyRange(modules, startKey, endKey, keyName); +} + +void BibleTextModelBuilder::updateKeyRange( + QList<const CSwordModuleInfo*> modules, + const QString& startKey, + const QString& endKey, + const QString& highlightKey) { + + m_model->clear(); + + const CSwordModuleInfo *module = modules.first(); + + QSharedPointer<CSwordKey> currentKey( CSwordKey::createInstance(module) ); + currentKey->setKey(highlightKey); + CSwordVerseKey* vk_current = dynamic_cast<CSwordVerseKey*>(currentKey.data()); + Q_ASSERT(vk_current); + m_currentVerse = vk_current->getVerse(); + + QSharedPointer<CSwordKey> lowerBound( CSwordKey::createInstance(module) ); + lowerBound->setKey(startKey); + + QSharedPointer<CSwordKey> upperBound( CSwordKey::createInstance(module) ); + upperBound->setKey(endKey); + + sword::SWKey* sw_start = dynamic_cast<sword::SWKey*>(lowerBound.data()); + sword::SWKey* sw_stop = dynamic_cast<sword::SWKey*>(upperBound.data()); + + Q_ASSERT((*sw_start == *sw_stop) || (*sw_start < *sw_stop)); + + // if (*sw_start == *sw_stop) { //same key, render single key + // return renderSingleKey(lowerBound->key(), modules); + // } + // else if (*sw_start < *sw_stop) { // Render range + // KeyTree tree; + // KeyTreeItem::Settings settings = keySettings; + + CSwordVerseKey* vk_start = dynamic_cast<CSwordVerseKey*>(lowerBound.data()); + Q_ASSERT(vk_start); + + CSwordVerseKey* vk_stop = dynamic_cast<CSwordVerseKey*>(upperBound.data()); + Q_ASSERT(vk_stop); + + while ((*vk_start < *vk_stop) || (*vk_start == *vk_stop)) { + + //make sure the key given by highlightKey gets marked as current key + // settings.highlight = (!highlightKey.isEmpty() ? (vk_start->key() == highlightKey) : false); + + /** + \todo We need to take care of linked verses if we render one or + (esp) more modules. If the verses 2,3,4,5 are linked to 1, + it should be displayed as one entry with the caption 1-5. + */ + + if (vk_start->getChapter() == 0) { // range was 0:0-1:x, render 0:0 first and jump to 1:0 + vk_start->setVerse(0); + addVerseToModel(vk_start); + vk_start->setChapter(1); + vk_start->setVerse(0); + } + addVerseToModel(vk_start); + if (!vk_start->next(CSwordVerseKey::UseVerse)) { + /// \todo Notify the user about this failure. + break; + } + } +} + +void BibleTextModelBuilder::addVerseToModel(CSwordVerseKey* key) { + int verseNumber = key->getVerse(); + QString verse; + if (verseNumber != 0) + verse.setNum(verseNumber); + QString text = key->renderedText(); + if (text.isEmpty()) + return; + text.replace("<br /><br />", "<br />"); + QStandardItem* item = new QStandardItem(); + item->setData(verse, BookEntry::ReferenceRole); + item->setData(text, BookEntry::TextRole); + m_model->appendRow(item); + + if (m_currentVerse == verseNumber) + m_currentModelIndex = m_model->rowCount() - 1; +} + +int BibleTextModelBuilder::getCurrentModelIndex() const { + return m_currentModelIndex; +} + +} diff --git a/src/mobile/models/bibletextmodelbuilder.h b/src/mobile/models/bibletextmodelbuilder.h new file mode 100644 index 0000000..620810a --- /dev/null +++ b/src/mobile/models/bibletextmodelbuilder.h @@ -0,0 +1,46 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "mobile/models/roleitemmodel.h" +#include <QList> +#include <QString> +#include "backend/drivers/cswordmoduleinfo.h" + +class CSwordVerseKey; + +namespace btm { + +class BibleTextModelBuilder { +public: + BibleTextModelBuilder(RoleItemModel* model); + + void updateModel( + QList<const CSwordModuleInfo*> modules, + const QString& keyText); + + void updateKeyRange( + QList<const CSwordModuleInfo*> modules, + const QString& startKey, + const QString& endKey, + const QString& highlightKey); + + int getCurrentModelIndex() const; + +private: + void addVerseToModel(CSwordVerseKey* key); + + RoleItemModel* m_model; + int m_currentVerse; + int m_currentModelIndex; +}; + +} diff --git a/src/mobile/models/booktextmodelbuilder.cpp b/src/mobile/models/booktextmodelbuilder.cpp new file mode 100644 index 0000000..44d5d92 --- /dev/null +++ b/src/mobile/models/booktextmodelbuilder.cpp @@ -0,0 +1,101 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "booktextmodelbuilder.h" + +#include "btglobal.h" +#include "backend/keys/cswordtreekey.h" +#include "backend/drivers/cswordbookmoduleinfo.h" +#include "backend/managers/cswordbackend.h" + +namespace btm { + +struct BookEntry { + enum TextRoles { + ReferenceRole = Qt::UserRole + 1, + TextRole = Qt::UserRole + 2 + }; +}; + +BookTextModelBuilder::BookTextModelBuilder(RoleItemModel* model) + : m_model(model) { + QHash<int, QByteArray> roleNames; + roleNames[BookEntry::ReferenceRole] = "ref"; + roleNames[BookEntry::TextRole] = "line"; + m_model->setRoleNames(roleNames); +} + +void BookTextModelBuilder::updateModel( + QList<const CSwordModuleInfo*> modules, + const QString& keyName) { + + Q_ASSERT( modules.count() >= 1 ); + Q_ASSERT( !keyName.isEmpty() ); + + FilterOptions options; + options.footnotes = 0; + options.strongNumbers = 0; + options.headings = 1; + options.morphTags = 0; + options.lemmas = 0; + options.hebrewPoints = 0; + options.greekAccents = 0; + options.textualVariants = 0; + options.redLetterWords = 1; + options.scriptureReferences = 0; + options.morphSegmentation = 0; + CSwordBackend::instance()->setFilterOptions(options); + + const CSwordModuleInfo *module = modules.first(); + + const CSwordBookModuleInfo* book = dynamic_cast<const CSwordBookModuleInfo*>(module); + Q_ASSERT(book); + + QSharedPointer<CSwordTreeKey> key ( + dynamic_cast<CSwordTreeKey*>( CSwordKey::createInstance(book) ) + ); + key->setKey(keyName); //set the key to position we'd like to get + +// const unsigned long offset = key->getOffset(); + + //check whether there's an intro we have to include + Q_ASSERT((module->type() == CSwordModuleInfo::GenericBook)); + + if (module->type() == CSwordModuleInfo::GenericBook) { + CSwordTreeKey* swKey = dynamic_cast<CSwordTreeKey*>(key.data()); + addVerseToModel(swKey); + } +} + +void BookTextModelBuilder::addVerseToModel(CSwordTreeKey* key) { +// int verseNumber = key->getVerse(); + QString verse; +// if (verseNumber != 0) +// verse.setNum(verseNumber); + QString text = key->renderedText(); // TODO - fix + if (text.isEmpty()) + return; +// text.replace("<br /><br />", "<br />"); + QStandardItem* item = new QStandardItem(); + item->setData(verse, BookEntry::ReferenceRole); + item->setData(text, BookEntry::TextRole); + m_model->appendRow(item); + +// if (m_currentVerse == verseNumber) +// m_currentModelIndex = m_model->rowCount() - 1; +} + +int BookTextModelBuilder::getCurrentModelIndex() const { + return m_currentModelIndex; +} + +} diff --git a/src/mobile/models/booktextmodelbuilder.h b/src/mobile/models/booktextmodelbuilder.h new file mode 100644 index 0000000..a64c380 --- /dev/null +++ b/src/mobile/models/booktextmodelbuilder.h @@ -0,0 +1,40 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "mobile/models/roleitemmodel.h" +#include <QList> +#include <QString> +#include "backend/drivers/cswordmoduleinfo.h" + +class CSwordTreeKey; + +namespace btm { + +class BookTextModelBuilder { +public: + BookTextModelBuilder(RoleItemModel* model); + + void updateModel( + QList<const CSwordModuleInfo*> modules, + const QString& keyText); + + int getCurrentModelIndex() const; + +private: + void addVerseToModel(CSwordTreeKey* key); + + RoleItemModel* m_model; + int m_currentVerse; + int m_currentModelIndex; +}; + +} diff --git a/src/mobile/models/roleitemmodel.cpp b/src/mobile/models/roleitemmodel.cpp new file mode 100644 index 0000000..95634af --- /dev/null +++ b/src/mobile/models/roleitemmodel.cpp @@ -0,0 +1,54 @@ +#include "roleitemmodel.h" + +/* Example usage: + +Enumerate the role ID's somewhere +--------------------------------- + +struct RedditEntry { + + enum RedditRoles { + UrlRole = Qt::UserRole + 1, + DescRole, + ... + }; + ... +} + +Instantiate the class +--------------------- + + QHash<int, QByteArray> roleNames; + roleNames[RedditEntry::UrlRole] = "url"; + roleNames[RedditEntry::ScoreRole] = "score"; + m_linksmodel = new RoleItemModel(roleNames); + +Populate with data: +------------------- + + QStandardItem* it = new QStandardItem(); + it->setData(e.desc, RedditEntry::DescRole); + it->setData(e.score, RedditEntry::ScoreRole); + + m_linksmodel->appendRow(it); + +Expose to QML: +------------- + +QDeclarativeContext *ctx = ... + +ctx->setContextProperty("mdlLinks", m_linksmodel); + +*/ + +//RoleItemModel::RoleItemModel(const QHash<int, QByteArray> &roleNames) +// : m_roleNames(roleNames) { +//} + +QHash<int, QByteArray> RoleItemModel::roleNames() const { + return m_roleNames; +} + +void RoleItemModel::setRoleNames(const QHash<int, QByteArray> &roleNames) { + m_roleNames = roleNames; +} diff --git a/src/mobile/models/roleitemmodel.h b/src/mobile/models/roleitemmodel.h new file mode 100644 index 0000000..46f02be --- /dev/null +++ b/src/mobile/models/roleitemmodel.h @@ -0,0 +1,24 @@ +#ifndef ROLEITEMMODEL_H +#define ROLEITEMMODEL_H + +#include <QStandardItemModel> + +/* class to allow easily exposing + C++ data as a model for QML View. +*/ + +class RoleItemModel : public QStandardItemModel { +public: + // roleNames is a map describing what role id (e.g. Qt::UserRole+1) + // is associated with what name on QML side (e.g. 'bookTitle') + // RoleItemModel(const QHash<int, QByteArray> &roleNames); + + QHash<int, QByteArray> roleNames() const; + void setRoleNames(const QHash<int, QByteArray> &roleNames); + +private: + QHash<int, QByteArray> m_roleNames; + +}; + +#endif // ROLEITEMMODEL_H diff --git a/src/mobile/qml/ContextMenu.qml b/src/mobile/qml/ContextMenu.qml new file mode 100644 index 0000000..bf55ebf --- /dev/null +++ b/src/mobile/qml/ContextMenu.qml @@ -0,0 +1,62 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: contextMenu + + property alias model: menuList.model + + signal accepted(string action) + + color: "white" + border.color: "black" + border.width: 1 + anchors.centerIn: parent + height: 250 + width: 250 + + onVisibleChanged: PropertyAnimation { + target: settings + property: "opacity" + from: 0 + to: 1 + duration: 400 + easing.type: Easing.InOutCubic + } + + BtStyle { + id: btStyle + } + + ListView { + id: menuList + + anchors.fill: parent + anchors.topMargin: 100 + + delegate: Rectangle { + color: "white" + border.color: "black" + border.width: 1 + width: parent.width + height: children[0].height * 2.5 + + Text { + id: menuText + x: 40 + anchors.verticalCenter: parent.verticalCenter + text: title + color: "black" + font.pointSize: btStyle.uiFontPointSize + } + + MouseArea { + anchors.fill: parent + onClicked: { + contextMenu.visible = false; + contextMenu.accepted(action); + } + } + } + } +} diff --git a/src/mobile/qml/FontSizeSlider.qml b/src/mobile/qml/FontSizeSlider.qml new file mode 100644 index 0000000..6c11dc0 --- /dev/null +++ b/src/mobile/qml/FontSizeSlider.qml @@ -0,0 +1,139 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: fontPointSize + + property string title: "" + property int min: 10 + property int max: 22 + property int current: 12 + property int previous: 12 + + signal accepted(int pointSize); + + color: "#f8f8f8" + border.color: "black" + border.width: 1 + anchors.centerIn: parent + width: parent.width * 0.85 + height: 140 + + Text { + text: title + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 10 + height: 40 + font.pointSize: btStyle.uiFontPointSize + } + + Rectangle { + id: bar + + color: "blue" + width: parent.width *.80 + height: 3 + anchors.centerIn: parent + } + + Rectangle { + id: indicator + + width: 18 + height: 18 + color: "red" + y: bar.y - height / 2 + x: { + var range = fontPointSize.max - fontPointSize.min; + var xpos = bar.width * + (fontPointSize.current - fontPointSize.min) / range; + xpos = xpos + bar.x + return xpos + } + } + + MouseArea { + property bool active: false + width: bar.width + anchors.left: bar.left + height: 40 + anchors.verticalCenter: bar.verticalCenter + + onPressed: { + active = true; + } + + onReleased: { + active = false; + } + + onMouseXChanged: { + if ( ! active) + return; + var range = fontPointSize.max - fontPointSize.min; + var currentF = mouse.x / bar.width * range + fontPointSize.min; + var value = Math.round(currentF); + if (value < fontPointSize.min) + value = min; + if (value > fontPointSize.max) + value = max; + fontPointSize.current = value; + accepted(value); + } + + } + + Grid { + id: buttons + + spacing: 10 + columns: 2 + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.rightMargin: 10 + anchors.bottomMargin: 10 + + Rectangle { + height: 40 + width: 120 + border.color: "black" + border.width: 1 + + Text { + text: "Ok" + anchors.centerIn: parent + font.pointSize: btStyle.uiFontPointSize + } + + MouseArea { + anchors.fill: parent + onClicked: { + fontPointSize.visible = false; + } + } + } + + Rectangle { + height: 40 + width: 120 + border.color: "black" + border.width: 1 + + Text { + text: "Cancel" + anchors.centerIn: parent + font.pointSize: btStyle.uiFontPointSize + } + + MouseArea { + anchors.fill: parent + onClicked: { + accepted(previous); + fontPointSize.visible = false; + } + } + } + } + +} diff --git a/src/mobile/qml/GridChooser.qml b/src/mobile/qml/GridChooser.qml new file mode 100644 index 0000000..b4d1612 --- /dev/null +++ b/src/mobile/qml/GridChooser.qml @@ -0,0 +1,117 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: gridChooser + + property int columns: 5 + property int rows: 5 + property int buttonWidth: 100 + property int buttonHeight: 30 + property int topMargin: 10 + property int leftMargin: 10 + property int titleHeight: 20 + property int space:5 + property string selected: "" + property string titleText: "" + property int maxLength: 0 + + signal accepted(string choosenText); + signal canceled(); + + onVisibleChanged: { + + var count = gridChooserModel.length + if (count < 36) + count = 36; + + calculateColumns(count); + + buttonWidth = (width-50)/columns; + buttonHeight = Math.floor((height-(rows*5))/rows); + + topMargin = (height - rows*(buttonHeight+space) + space)/2 +titleHeight; + leftMargin = (width - columns*(buttonWidth+space) + space)/2; + } + + function calculateColumns(count) { + var aspectRatio = 0.175; + var columnsF = Math.sqrt(count * width * aspectRatio / height); + columns = Math.ceil(columnsF); + rows = Math.ceil((count-0.01)/columns); + } + + function accept(value) { + visible = false; + gridChooser.accepted(value); + } + + Text { + id: title + + text: titleText + font.pointSize: btStyle.uiFontPointSize + height: titleHeight + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + } + + BtStyle { + id: btStyle + } + + MouseArea { + id: mouseArea + + anchors.fill: parent + enabled: gridChooser.opacity + } + + Rectangle { + anchors.fill: parent + color: btStyle.buttonBackground + } + + Rectangle { + id: topSpace + + width: leftMargin + height: topMargin + color: btStyle.buttonBackground + } + + Grid { + id: grid + + anchors.top: topSpace.bottom + anchors.bottom: bottom.top + anchors.left: topSpace.right + anchors.right: parent.right + columns: gridChooser.columns + spacing: gridChooser.space + + Repeater { + id: repeater + + model: gridChooserModel + + GridChooserButton { + id: buttonX + + text: modelData + textHeight: btStyle.uiFontPointSize + buttonWidth: gridChooser.buttonWidth + buttonHeight: gridChooser.buttonHeight + textColor: { + if (text == gridChooser.selected) + return btStyle.buttonHighlightedText + else + return btStyle.buttonTextColor + } + buttonColor: btStyle.buttonColor + activeButtonColor: btStyle.buttonTextColor + onClicked: gridChooser.accept(text) + } + } + } +} diff --git a/src/mobile/qml/GridChooserButton.qml b/src/mobile/qml/GridChooserButton.qml new file mode 100644 index 0000000..9a65041 --- /dev/null +++ b/src/mobile/qml/GridChooserButton.qml @@ -0,0 +1,52 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: button + + property int buttonWidth + property int buttonHeight + property int textHeight + property color textColor + property color buttonColor + property color activeButtonColor + property alias text: buttonText.text + + signal clicked + + width: buttonWidth + height: buttonHeight + gradient: Gradient { + GradientStop { position: 0.0; color: btStyle.buttonGradient0 } + GradientStop { position: 0.15; color: btStyle.buttonGradient1 } + GradientStop { position: 0.85; color: btStyle.buttonGradient2 } + GradientStop { position: 1.0; color: btStyle.buttonGradient3 } + } + smooth: true + + border { + width: 1 + color: btStyle.buttonBorder + } + + BtStyle { + id: btStyle + } + + Text { + id: buttonText + + width: buttonWidth-8 + anchors.centerIn: parent + color: button.textColor + font.pointSize: parent.textHeight + elide: Text.ElideRight + } + + MouseArea { + id: mouseArea + + anchors.fill: parent + onClicked: button.clicked() + } +} diff --git a/src/mobile/qml/ImageButton.qml b/src/mobile/qml/ImageButton.qml new file mode 100644 index 0000000..552a9b4 --- /dev/null +++ b/src/mobile/qml/ImageButton.qml @@ -0,0 +1,24 @@ +import QtQuick 2.1 + +Rectangle { + id: imageButton + + property bool show: true + property string icon: "" + property int corner: 6 + + border.width: 1 + border.color: "gray" + radius: corner + + Image{ + id: nextIcon + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: imageButton.icon + height: parent.height + width: parent.height + anchors.right: parent.right + anchors.top: parent.top + } +} diff --git a/src/mobile/qml/InstallManagerChooser.qml b/src/mobile/qml/InstallManagerChooser.qml new file mode 100644 index 0000000..15b6079 --- /dev/null +++ b/src/mobile/qml/InstallManagerChooser.qml @@ -0,0 +1,153 @@ +import QtQuick 2.1 + +Rectangle { + id: installManager + + property alias sourceModel: sourceView.model + property alias categoryModel: categoryView.model + property alias languageModel: languageView.model + property alias worksModel: worksView.model + property alias sourceIndex: sourceView.currentIndex + property alias categoryIndex: categoryView.currentIndex + property alias languageIndex: languageView.currentIndex + property int spacing: 8 + + objectName: "installManager" + color: "lightgray" + border.color: "black" + border.width: 2 + + signal sourceChanged(int index); + signal categoryChanged(int index); + signal languageChanged(int index); + signal workSelected(int index); + signal cancel(); + signal installRemove(); + signal refreshLists(); + + Grid { + id: grid + columns: 3 + rows: 1 + spacing: installManager.spacing + width: parent.width - installManager.spacing + height: installManager.height/3 + anchors.left: parent.left + anchors.top: parent.top + anchors.margins: installManager.spacing + + ListTextView { + id: sourceView + onItemSelected: { + sourceChanged(currentIndex) + } + + title: "Source" + width: parent.width/3 - grid.spacing + height: installManager.height/3 + } + + ListTextView { + id: categoryView + + title: "Category" + width: parent.width/3 - grid.spacing + height: installManager.height/3 + onItemSelected: { + categoryChanged(currentIndex) + } + } + + ListTextView { + id: languageView + + title: "Language" + width: parent.width/3 - grid.spacing + height: installManager.height/3 + onItemSelected: { + languageChanged(currentIndex) + } + } + } + + ListWorksView { + id: worksView + + title: "Work" + width: parent.width - 2 * installManager.spacing + anchors.top: grid.bottom + anchors.left: parent.left + anchors.bottom: installRemoveButton.top + anchors.margins: installManager.spacing + onItemSelected: { + workSelected(index) + } + } + + Rectangle { + id: "refreshButton" + width:150 + height: 40 + anchors.bottom: parent.bottom + anchors.bottomMargin: 10 + anchors.right: installRemoveButton.left + anchors.rightMargin: 10 + border.width: 1 + border.color: "black" + + Text { + text: "Refresh Lists" + anchors.centerIn: parent + } + + MouseArea { + anchors.fill: parent + onClicked: installManager.refreshLists() + } + } + + Rectangle { + id: "installRemoveButton" + width:150 + height: 40 + anchors.bottom: parent.bottom + anchors.bottomMargin: 10 + anchors.right: cancelButton.left + anchors.rightMargin: 10 + border.width: 1 + border.color: "black" + + Text { + text: "Install / Remove" + anchors.centerIn: parent + } + + MouseArea { + anchors.fill: parent + onClicked: installManager.installRemove() + } + } + + Rectangle { + id: "cancelButton" + width: installRemoveButton.width + height: installRemoveButton.height + anchors.bottom: parent.bottom + anchors.bottomMargin: 10 + anchors.right: parent.right + anchors.rightMargin: 10 + border.width: 1 + border.color: "black" + + Text { + text: "Cancel" + anchors.centerIn: parent + } + + MouseArea { + anchors.fill: parent + onClicked: installManager.cancel(); + } + } + +} diff --git a/src/mobile/qml/ListTextView.qml b/src/mobile/qml/ListTextView.qml new file mode 100644 index 0000000..703fe48 --- /dev/null +++ b/src/mobile/qml/ListTextView.qml @@ -0,0 +1,108 @@ +import QtQuick 2.1 + +Rectangle { + id: top + + property alias model: listView.model + property alias currentIndex: listView.currentIndex + property alias title: title.text + property bool highlight: true + + border.color: "black" + border.width: 2 + + signal itemSelected(int index) + + Rectangle { + id: titleRect + + border.color: "black" + border.width: 1 + height:25 + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.leftMargin: 3 + anchors.rightMargin: 3 + anchors.topMargin: 3 + + Text { + id: title + anchors.horizontalCenter: parent.horizontalCenter + anchors.centerIn: parent + horizontalAlignment: Text.AlignCenter + verticalAlignment: Text.AlignBottom + style: Text.Sunken + font.pointSize: btStyle.uiFontPointSize + } + } + + ListView { + id: listView + + anchors.top: titleRect.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 3 + anchors.rightMargin: 3 + anchors.bottomMargin: 3 + clip: true + highlightFollowsCurrentItem: true + currentIndex: 2 + + function selectItem(x, y) { + var index = listView.indexAt(x+contentX,y+contentY); + currentIndex = index; + top.itemSelected(index); + } + + Rectangle { + id: scrollbar + anchors.right: listView.right + y: listView.visibleArea.yPosition * listView.height + width: 7 + height: listView.visibleArea.heightRatio * listView.height + color: "black" + visible: listView.visibleArea.heightRatio < 0.99 + } + + delegate { + Rectangle { + id: entry + + property bool selected: ListView.isCurrentItem ? true : false + objectName: "entry" + color: (highlight && ListView.isCurrentItem) ? "#ffeeaa" : "white" + border.width: 1 + border.color: "darkgray" + width: parent.width + height: 40 + + Text { + id: entryText + + anchors.top: entry.top + anchors.left: entry.left + anchors.right: entry.right + width: parent.width + anchors.leftMargin: 10 + anchors.rightMargin: 10 + anchors.topMargin: 10 + text: modelText + font.pointSize: btStyle.uiFontPointSize + font.bold: highlight && entry.selected + } + } + } + + MouseArea { + anchors.fill: listView + onClicked: itemSelected() + + function itemSelected() { + listView.selectItem(mouseX, mouseY); + } + } + } +} diff --git a/src/mobile/qml/ListWorksView.qml b/src/mobile/qml/ListWorksView.qml new file mode 100644 index 0000000..6e6dd13 --- /dev/null +++ b/src/mobile/qml/ListWorksView.qml @@ -0,0 +1,123 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: top + property alias model: listView.model + property alias title: title.text + + border.color: "black" + border.width: 2 + + signal itemSelected(int index) + + Rectangle { + id: titleRect + + border.color: "black" + border.width: 1 + height:25 + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.leftMargin: 3 + anchors.rightMargin: 3 + anchors.topMargin: 3 + + Text { + id: title + anchors.horizontalCenter: parent.horizontalCenter + anchors.centerIn: parent + horizontalAlignment: Text.AlignCenter + verticalAlignment: Text.AlignBottom + style: Text.Sunken + font.pointSize: btStyle.uiFontPointSize + } + } + + ListView { + id: listView + clip: true + anchors.top: titleRect.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 3 + + function itemSelected(index) { + top.itemSelected(index); + } + + Rectangle { + id: scrollbar + anchors.right: listView.right + y: listView.visibleArea.yPosition * listView.height + width: 5 + height: listView.visibleArea.heightRatio * listView.height + color: "black" + visible: listView.visibleArea.heightRatio < 0.99 + } + + delegate { + Rectangle { + id: entry + + color: "white" + border.width: 1 + border.color: ListView.isCurrentItem ? "#c0c0c0" : "#a0a0a0" + width: parent.width + height: 60 + + Image { + id: installedCheckmark + + source: "checkmark.svg" + height: entry.height - 15 + width: 25 + anchors.left: parent.left + anchors.top: parent.top + anchors.leftMargin: 5 + anchors.topMargin: 5 + visible: installed == 1 + } + + MouseArea { + anchors.fill: parent + onClicked: {listView.itemSelected(index)} + } + + Text { + anchors.top: entry.top + anchors.left: installedCheckmark.right + anchors.right: entry.right + width: parent.width + height: parent.height/2 -4 + anchors.leftMargin: 10 + anchors.rightMargin: 10 + anchors.topMargin: 5 + text: title + font.pointSize: btStyle.textFontPointSize + } + + Text { + anchors.bottom: entry.bottom + anchors.left: installedCheckmark.right + anchors.right: entry.right + width: parent.width + height: parent.height/2 -4 + anchors.leftMargin: 35 + anchors.rightMargin: 10 + anchors.topMargin: 25 + text: desc + elide: Text.ElideMiddle + font.pointSize: btStyle.textFontPointSize + } + } + } + + BtStyle { + id: btStyle + } + } +} + diff --git a/src/mobile/qml/MainToolbar.qml b/src/mobile/qml/MainToolbar.qml new file mode 100644 index 0000000..66513b2 --- /dev/null +++ b/src/mobile/qml/MainToolbar.qml @@ -0,0 +1,27 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: toolbar + + signal buttonClicked + + BtStyle { + id: btStyle + } + + color: btStyle.toolbarColor + z:0 + + MenuButton { + id: menuButton + + width: parent.height + height: parent.height + anchors.right: parent.right + anchors.top: parent.top + onButtonClicked: { + toolbar.buttonClicked() + } + } +} diff --git a/src/mobile/qml/MenuButton.qml b/src/mobile/qml/MenuButton.qml new file mode 100644 index 0000000..b3ba458 --- /dev/null +++ b/src/mobile/qml/MenuButton.qml @@ -0,0 +1,30 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: menuButton + + signal buttonClicked + + color: "black" + + BtStyle { + id: btStyle + } + + Column { + spacing:3 + + Rectangle { color: "white"; width:2; height:2 } + Rectangle { color: "white"; width:2; height:2 } + Rectangle { color: "white"; width:2; height:2 } + + anchors.centerIn: parent + } + MouseArea { + anchors.fill: parent + onClicked: { + menuButton.buttonClicked() + } + } +} diff --git a/src/mobile/qml/MenuView.qml b/src/mobile/qml/MenuView.qml new file mode 100644 index 0000000..01b5142 --- /dev/null +++ b/src/mobile/qml/MenuView.qml @@ -0,0 +1,28 @@ +import QtQuick 2.1 + +Column { + id: menus + + width:120 + height:20 * listModel.count + anchors.top: mainToolbar.bottom + anchors.right: mainToolbar.right + z: 100 + visible: false + + Repeater { + model: listModel + delegate: Rectangle { + width:parent.width + height:24 + color: btStyle.menu + border.color: btStyle.menuBorder + border.width: 1 + Text { + anchors.centerIn: parent + text: title + color: btStyle.menuText + } + } + } +} diff --git a/src/mobile/qml/Menus.qml b/src/mobile/qml/Menus.qml new file mode 100644 index 0000000..1a9e53b --- /dev/null +++ b/src/mobile/qml/Menus.qml @@ -0,0 +1,61 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: menu + + property alias model: menusRepeater.model + property int fontPointSize: 15 + property int menuHeight: 70 + property int topMenuMargin: 150 + property int leftMenuMargin: 50 + + signal menuSelected(string action) + + visible: false + anchors.fill: parent + color: "#f0f0f0" + + BtStyle { + id: btStyle + } + + Component { + id: eachMenu + + Rectangle { + width: menu.width + height: menuHeight + color: "white" + border.color: "#f0f0f0" + border.width: 2 + + Text { + text: title + font.pointSize: btStyle.uiFontPointSize + color: "black" + anchors.fill: parent + anchors.leftMargin: leftMenuMargin + verticalAlignment: Text.AlignVCenter + + MouseArea { + anchors.fill: parent + onClicked: { + menu.menuSelected(action); + } + } + } + } + } + + ListView { + id: menusRepeater + + delegate: eachMenu + width: parent.width + anchors.fill: parent + anchors.topMargin: topMenuMargin + + } +} + diff --git a/src/mobile/qml/ModuleChooser.qml b/src/mobile/qml/ModuleChooser.qml new file mode 100644 index 0000000..49d19d1 --- /dev/null +++ b/src/mobile/qml/ModuleChooser.qml @@ -0,0 +1,109 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: moduleChooser + + property alias categoryModel: categoryView.model + property alias languageModel: languageView.model + property alias worksModel: worksView.model + property alias categoryIndex: categoryView.currentIndex + property alias languageIndex: languageView.currentIndex + property alias moduleIndex: worksView.currentIndex + property int lastCategoryIndex: 0 + property int lastLanguageIndex: 0 + property int spacing: 5 + property string selectedModule: "" + property string selectedCategory: "" + + objectName: "moduleChooser" + color: "lightgray" + border.color: "black" + border.width: 2 + + onVisibleChanged: { + if (visible == true) { + moduleInterface.updateCategoryAndLanguageModels(); + categoryIndex = lastCategoryIndex; + languageIndex = lastLanguageIndex; + } + } + + onCategoryIndexChanged: { + if (visible == true) { + moduleInterface.updateWorksModel(); + } + } + + onLanguageIndexChanged: { + if (visible == true) { + moduleInterface.updateWorksModel(); + } + } + + signal categoryChanged(int index); + signal languageChanged(int index); + signal moduleSelected(); + + ModuleInterface { + id: moduleInterface + } + + Grid { + id: grid + columns: 2 + rows: 1 + spacing: parent.spacing + width: parent.width - moduleChooser.spacing + height: parent.height/2.5 + anchors.left: parent.left + anchors.top: parent.top + anchors.margins: parent.spacing + + ListTextView { + id: categoryView + + title: "Category" + width: grid.width/2 - grid.spacing + height: grid.height + onItemSelected: { + categoryChanged(currentIndex) + } + } + + ListTextView { + id: languageView + + title: "Language" + width: grid.width/2 - grid.spacing + height: grid.height + onItemSelected: { + languageChanged(currentIndex); + } + } + } + + ListTextView { + id: worksView + + title: "Work" + width: parent.width - 2 * parent.spacing + anchors.top: grid.bottom + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: moduleChooser.spacing + highlight: false + onItemSelected: { + selectedModule = moduleInterface.module(index); + selectedCategory = moduleInterface.category(index); + moduleSelected(); + moduleChooser.visible = false; + } + } + +// MouseArea { +// anchors.fill: parent +// onClicked: moduleChooser.cancel(); +// } +} + diff --git a/src/mobile/qml/Progress.qml b/src/mobile/qml/Progress.qml new file mode 100644 index 0000000..e5f75b3 --- /dev/null +++ b/src/mobile/qml/Progress.qml @@ -0,0 +1,63 @@ +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import BibleTime 1.0 + +Rectangle { + id: installProgress + + property alias minimumValue: progressBar.minimumValue + property alias value: progressBar.value + property alias maximumValue: progressBar.maximumValue + property alias text: label.text + + color: btStyle.buttonBackground + border.color: "black" + border.width: 5 + + signal cancel() + + BtStyle { + id: btStyle + } + + Text { + id: label + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: progressBar.top + anchors.bottomMargin: 20 + } + + ProgressBar { + id: progressBar + + anchors.centerIn: parent + width: parent.width - 100 + height: 16 + } + + Rectangle { + color: "white" + border.color: "black" + border.width: 1 + width: 100 + height:30 + anchors.top: progressBar.bottom + anchors.topMargin: 20 + anchors.horizontalCenter: parent.horizontalCenter + + Text { + anchors.centerIn: parent + text: "Cancel" + + } + + MouseArea { + anchors.fill: parent + onClicked: { + cancel(); + } + } + } +} diff --git a/src/mobile/qml/Settings.qml b/src/mobile/qml/Settings.qml new file mode 100644 index 0000000..391ce4c --- /dev/null +++ b/src/mobile/qml/Settings.qml @@ -0,0 +1,93 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: settings + + property int finalHeight: 300 + + color: "white" + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + height: parent.height + + onVisibleChanged: PropertyAnimation { + target: settings + property: "opacity" + from: 0 + to: 1 + duration: 200 + easing.type: Easing.InOutCubic + } + + BtStyle { + id: btStyle + } + + ListModel { + id: settingsModel + + ListElement { title: "Ui Font Size"; action: "uiSize" } + ListElement { title: "Window Arrangement"; action: "arrangement" } + } + + ListView { + id: settingsList + + anchors.fill: parent + anchors.topMargin: 100 + model: settingsModel + + delegate: Rectangle { + color: "white" + border.color: "lightgray" + border.width: 1 + width: parent.width + height: children[0].height * 2.5 + + Text { + id: menuText + x: 40 + anchors.verticalCenter: parent.verticalCenter + text: title + color: "black" + font.pointSize: btStyle.uiFontPointSize + } + + MouseArea { + anchors.fill: parent + onClicked: { + if (action == "arrangement") { + windowArrangementMenus.visible = true; + settings.visible = false; + } + else if (action == "uiSize") { + uiFontPointSize.visible = true; + settings.visible = false; + console.log("y") + } + } + } + } + } + + ImageButton { + id: backButton + + icon: "leftarrow.svg" + height: 36 + width: 56 + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottomMargin: 8 + visible: true + + MouseArea { + anchors.fill: parent + onClicked: { + settings.visible = false; + } + } + } +} diff --git a/src/mobile/qml/TreeChooser.qml b/src/mobile/qml/TreeChooser.qml new file mode 100644 index 0000000..5dc1eeb --- /dev/null +++ b/src/mobile/qml/TreeChooser.qml @@ -0,0 +1,167 @@ +import QtQuick 2.1 + +Rectangle { + id: treeChooser + + property ListModel model: ListModel { + } + property string path: "" + property int pathCount: 0 + + color: "white" + border.width: 2 + border.color: "black" + + signal back() + signal next(string childText) + signal select(string childText) + + Rectangle { + id: pathArea + + border.color: "black" + border.width: 0 + color: "white" + + height: {20 * pathCount } + anchors.right: parent.right + anchors.left: parent.left + anchors.top: parent.top + anchors.margins: 4 + visible: path.length > 0 + + function splitPath(path) { + var pathList = path.split("/"); + var newPath = ""; + var space = ""; + var count = pathList.length; + treeChooser.pathCount = count; + // pathList[0] is empty + for (var i=1; i< count; ++i) { + var pathI = pathList[i]; + newPath += space + pathI + "\n"; + space += " "; + } + return newPath; + } + + ImageButton { + id: backButton + + icon: "leftarrow.svg" + height: 36 + width: 56 + anchors.verticalCenter: parent.verticalCenter + anchors.right : parent.right + anchors.topMargin: 2 + visible: true + + MouseArea { + anchors.fill: parent + onClicked: { + treeChooser.back(); + } + } + } + + Text { + id: pathText + + text: pathArea.splitPath(treeChooser.path) + font.pointSize: 12 + height: parent.height +// width: parent.width - backButton.width -50 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: backButton.left + anchors.leftMargin: 10 + elide: Text.ElideRight + } + } + + ListView { + id: listView + + function next(index, name) { + treeChooser.next(name); + } + + function select(index, name) { + treeChooser.select(name); + } + + anchors.top: pathArea.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 30 + anchors.leftMargin: 4 + anchors.rightMargin: 4 + anchors.bottomMargin: 4 + boundsBehavior: Flickable.StopAtBounds + width: pathArea.width + model: treeChooser.model + delegate: + Rectangle { + id: entry + + property string action: "" + + + border.color: "#eeeeee" + border.width: 1 + width: parent.width + height: 40 + + Text { + id: entryText + + font.pointSize: 12 +// anchors.fill: entry + anchors.top: entry.top + anchors.left: entry.left + anchors.right: entry.right + width: 340 + anchors.leftMargin: 10 + anchors.rightMargin: 10 + anchors.topMargin: 10 + text: name + elide: Text.ElideRight + } + + ImageButton { + id: imageButton + icon: "rightarrow.svg" + + height: parent.height-4 + width: 56 + anchors.right: parent.right + anchors.top: parent.top + anchors.topMargin: 2 + visible: childcount > 0 + + MouseArea { + anchors.fill: parent + onClicked: { + listView.currentIndex = index + listView.next(index, name) + } + } + } + + MouseArea { + anchors.left: parent.left + anchors.right: imageButton.left + anchors.top: parent.top + anchors.bottom: parent.bottom + onClicked: { + listView.currentIndex = index + listView.select(index, name) + } + } + } + + snapMode: ListView.SnapToItem + focus: true + } +} diff --git a/src/mobile/qml/Window.qml b/src/mobile/qml/Window.qml new file mode 100644 index 0000000..a14131f --- /dev/null +++ b/src/mobile/qml/Window.qml @@ -0,0 +1,178 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: windowView + + property string title: toolbar.title + + function setModule(module) { + btWindowInterface.moduleName = module; + } + + function contextMenus() { +// contextMenu.visible = true; + } + + color: "black" + + BtWindowInterface { + id: btWindowInterface + } + + BtStyle { + id:btStyle + } + + Rectangle { + id: toolbar + + property string title: btWindowInterface.moduleName + " (" + btWindowInterface.reference + ")" + + width: parent.width + height: 36 + color: btStyle.toolbarColor + border.width: 1 + border.color: "black" + + Rectangle { + id: moduleDisplay + + width: text.width +10 + radius:btStyle.buttonRadius + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.topMargin: 4 + anchors.leftMargin: 5 + anchors.bottomMargin: 4 + color: btStyle.toolbarButton + border.color: btStyle.buttonBorder + border.width: 1 + + Text { + id: text + + anchors.centerIn: parent + anchors.leftMargin: 4 + anchors.rightMargin: 4 + font.pointSize: btStyle.uiFontPointSize + elide: Text.ElideMiddle + color: btStyle.toolbarButtonText + text: btWindowInterface.moduleName + } + + MouseArea { + id: moduleMouseArea + + anchors.fill: parent + onClicked: { + btWindowInterface.changeModule(); + } + } + } + + + Rectangle { + id: referenceDisplay + + width: { + var w1 = 300 + var w2 = toolbar.width - moduleDisplay.width; + var w = Math.min(w1,w2); + return w - 15; + } + radius: btStyle.buttonRadius + anchors.left: moduleDisplay.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.topMargin: 4 + anchors.bottomMargin: 4 + anchors.leftMargin: 5 + color: btStyle.toolbarButton + border.color: btStyle.buttonBorder + border.width: 1 + + Text { + id: referenceText + anchors.centerIn: parent + anchors.leftMargin: 6 + anchors.rightMargin: 4 + width: referenceDisplay.width - 4 + font.pointSize: btStyle.uiFontPointSize + elide: Text.ElideMiddle + color: btStyle.toolbarButtonText + text: btWindowInterface.reference + } + + MouseArea { + id: mouseArea + + anchors.fill: parent + onClicked: { + btWindowInterface.changeReference(); + } + } + } + + } + + Rectangle { + id: mainTextView + + color: "white" + anchors.top: toolbar.bottom + anchors.left: windowView.left + anchors.right: windowView.right + anchors.bottom: windowView.bottom + + ListView { + id: listView + + clip: true + anchors.fill: parent + anchors.leftMargin: 8 + anchors.rightMargin: 8 + model: btWindowInterface.textModel + currentIndex: btWindowInterface.currentModelIndex + delegate: Text { + text: "<font color=\"blue\">" + ref + "</font> " + line + width: parent.width + color: "black" + font.pointSize: btStyle.textFontPointSize + wrapMode: Text.WordWrap + } + + MouseArea { + + anchors.fill: parent + onDoubleClicked: { + windowView.contextMenus(); + } + + onPressAndHold: { + windowView.contextMenus(); + + } + } + } + } + + ListModel { + id: contextMenuModel + + ListElement { title: "Text Font Size"; action: "textSize" } + } + + ContextMenu { + id: contextMenu + + function doAction(action) { + } + + model: contextMenuModel + visible: false + Component.onCompleted: contextMenu.accepted.connect(contextMenu.doAction) + } + +} diff --git a/src/mobile/qml/WindowManager.qml b/src/mobile/qml/WindowManager.qml new file mode 100644 index 0000000..3a66219 --- /dev/null +++ b/src/mobile/qml/WindowManager.qml @@ -0,0 +1,291 @@ +import QtQuick 2.1 +import BibleTime 1.0 + + +Rectangle { + id: windowArea + + property var windows: [] + property int single: 0 + property int tabLayout: 1 + property int autoTile: 2 + property int autoTileHor: 3 + property int autoTileVer: 4 + property int windowLayout: single + + function setCurrentTabbedWindow(index) { + tabbedWindows.current = index; + } + + function setWindowArrangement(arrangement) { + if (arrangement < single || arrangement > autoTileVer) + return; + windowLayout = arrangement; + layoutWindows(); + } + + function createWindowMenus() { + windowsModel.clear(); + for (var i=0; i<windows.length; ++i) { + var window = windows[i]; + windowsModel.append ( + { title: window.title, action: i.toString() } + ) + } + windowTitlesMenus.model = windowsModel + windowTitlesMenus.visible = true; + } + + + function newWindow() { + moduleChooser.moduleSelected.connect(openWindowSlot); + moduleChooser.visible = true; + } + + function openWindowSlot() { + moduleChooser.moduleSelected.disconnect(openWindowSlot); + openWindow(moduleChooser.selectedCategory, moduleChooser.selectedModule) + } + + function openWindow(category, module) { + if (category == "Bibles") + component = Qt.createComponent("Window.qml"); + else if (category == "Commentaries") + component = Qt.createComponent("Window.qml"); + else if (category == "Books") + component = Qt.createComponent("Window.qml"); + else { + console.log(category, " are not yet supported."); + return; + } + + window = component.createObject(null, {"width": 250, "height": 200}); + window.setModule(module); + + if (window == null) { + // Error Handling + console.log("Error creating object"); + } + else { + windows.push(window) + layoutWindows(); + var curWindow = windows.length -1; + selectWindow(curWindow); + } + } + + function layoutTiles(rows, columns) + { + gridWindows.columns = columns; + gridWindows.rows = rows; + var width = gridWindows.width/columns -2; + var height = gridWindows.height/rows -2; + + for (var i=0; i<windows.length; ++i) { + var window = windows[i]; + window.anchors.fill = undefined + window.height = height; + window.width = width; + window.parent = gridWindows; + } + } + + function arrangeSingleWindow() { + tabbedWindows.z = 1; + tabbedWindows.tabVisible = false; + for (var i=0; i<windows.length; ++i) { + var window = windows[i]; + window.parent = tabbedWindowsStack; + window.anchors.fill = tabbedWindowsStack + } + } + + function arrangeTabbedWindows() { + tabbedWindows.z = 1; + tabbedWindows.tabVisible = true; + for (var i=0; i<windows.length; ++i) { + var window = windows[i]; + window.parent = tabbedWindowsStack; + window.anchors.fill = tabbedWindowsStack + } + } + + function arrangeTiledWindows() { + gridWindows.z = 1; + var columns = 1; + var rows = 1; + var count = windows.length; + + if (windowLayout == autoTile) { + if (count > 1) { + columns = 2 + rows = Math.floor((count+1)/2); + } + } + else if (windowLayout == autoTileHor) + { + rows = count; + } + else if (windowLayout == autoTileVer) + { + columns = count; + } + layoutTiles(rows, columns); + } + + function layoutWindows() { + tabbedWindows.z = -2; + gridWindows.z = -3; + + if (windowLayout == single) { + arrangeSingleWindow(); + } + else if (windowLayout == tabLayout) { + arrangeTabbedWindows(); + } + else { + arrangeTiledWindows(); + } + } + + function selectWindow(n) { + if (windowLayout == tabLayout || windowLayout == single) { + tabbedWindows.current = n; + } + } + +// anchors.top: spacer.bottom +// anchors.left: parent.left +// anchors.right: parent.right +// anchors.bottom: parent.bottom +// color: "#646464" + + Grid { + id: gridWindows + + objectName: "gridWindows" + anchors.fill: parent + columns: 2 + spacing: 2 + z: 2 + } + + Item { + id: tabbedWindows + + default property alias content: tabbedWindowsStack.children + property bool tabVisible: true + property int current: 0 + + function changeTabs() { + setOpacities(); + } + + function setOpacities() { + for (var i = 0; i < tabbedWindowsStack.children.length; ++i) { + tabbedWindowsStack.children[i].z = (i == current ? 1 : 0) + } + } + + objectName: "tabbedWindows" + anchors.fill: parent + onCurrentChanged: changeTabs() + Component.onCompleted: changeTabs() + + Row { + id: header + + objectName: "header" + + Repeater { + id: tabRepeater + + function setColors() { + if (tabbedWindows.current == tabbedWindowsStack.index) { + tabImage.color = btStyle.windowTabSelected + tabText.color = btStyle.windowTabTextSelected + } + else { + tabImage.color = btStyle.windowTab + tabText.color = btStyle.windowTabText + } + } + + model: tabbedWindowsStack.children.length + delegate: Rectangle { + id: tab + + function calculateTabWidth() { + var tabWidth = (tabbedWindows.width) / tabbedWindowsStack.children.length; + return tabWidth; + } + + visible: tabbedWindows.tabVisible + //width: (tabbedWindows.width) / tabbedWindowsStack.children.length; + width: { + calculateTabWidth() + } + height: 36 + + Rectangle { + id: tabBorder + width: parent.width; height: 1 + anchors { bottom: parent.bottom; bottomMargin: 1 } + color: "#acb2c2" + } + + Rectangle { + id: tabImage + + anchors { fill: parent; leftMargin: 8; topMargin: 4; rightMargin: 8 } + color: { + if (tabbedWindows.current == index) + return btStyle.windowTabSelected + else + return btStyle.windowTab + } + border.color: btStyle.windowTab + border.width: 2 + + Text { + id: tabText + + horizontalAlignment: Qt.AlignHCenter; + verticalAlignment: Qt.AlignVCenter + anchors.fill: parent + anchors.topMargin: 6 + font.pointSize: btStyle.uiFontPointSize -3 + text: tabbedWindowsStack.children[index].title + elide: Text.ElideLeft + color: { + if (tabbedWindows.current == index) + return btStyle.windowTabTextSelected + else + return btStyle.windowTabText + } + } + } + + MouseArea { + id: tabMouseArea + + anchors.fill: parent + onClicked: { + tabbedWindows.current = index + } + } + } + } + } + + Item { + id: tabbedWindowsStack + + objectName: "tabbedWindowsStack" + width: parent.width + anchors.top: header.bottom; + anchors.bottom: tabbedWindows.bottom + } + } + +} diff --git a/src/mobile/qml/checkmark.svg b/src/mobile/qml/checkmark.svg new file mode 100644 index 0000000..07a3ad8 --- /dev/null +++ b/src/mobile/qml/checkmark.svg @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + 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="450" height="400" viewBox="85 145 450 400" + sodipodi:version="0.32" + inkscape:version="0.45" + sodipodi:docname="checkmark.svg"> + <metadata> + <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> + <path + style="fill:#5fd35f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 508.74477,226.99015 C 459.42189,193.17234 436.08559,163.59563 436.08559,163.59563 C 344.99984,217.26626 248.26757,407.83719 248.26757,407.83719 C 202.93454,344.01939 157.35384,326.21932 157.35384,326.21932 C 136.86236,353.60112 101.54091,390.09316 101.54091,390.09316 C 183.924,412.28062 253.07323,493.70015 253.07323,493.70015 C 402.5571,259.01322 508.74477,226.99015 508.74477,226.99015 z " + sodipodi:nodetypes="ccccccc" /> + <path + sodipodi:type="arc" + style="opacity:0.2;fill:#999999;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0" + sodipodi:cx="238.57143" + sodipodi:cy="529.50507" + sodipodi:rx="64.285713" + sodipodi:ry="7.1428571" + d="M 302.03011,528.36301 A 64.285713,7.1428571 0 1 1 301.97855,528.32818" + sodipodi:start="6.1226078" + sodipodi:end="12.400852" + sodipodi:open="true" + transform="translate(8.5714285,-11.428571)" /> + <path + style="opacity:0.27777782;fill:#5fd35f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 518.74479,227.27587 C 469.42191,193.45806 446.08561,163.88135 446.08561,163.88135 C 354.99986,217.55198 258.26759,408.12291 258.26759,408.12291 C 212.93456,344.30511 167.35386,326.50504 167.35386,326.50504 C 146.86238,353.88684 111.54093,390.37888 111.54093,390.37888 C 193.92402,412.56634 263.07325,493.98587 263.07325,493.98587 C 412.55712,259.29894 518.74479,227.27587 518.74479,227.27587 z " + sodipodi:nodetypes="ccccccc" /> +</svg> diff --git a/src/mobile/qml/leftarrow.svg b/src/mobile/qml/leftarrow.svg new file mode 100644 index 0000000..6143c87 --- /dev/null +++ b/src/mobile/qml/leftarrow.svg @@ -0,0 +1,83 @@ +<?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="900" + height="900" + id="svg2" + version="1.1" + inkscape:version="0.48.4 r9939" + sodipodi:docname="rightarrow.svg"> + <defs + id="defs4" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.74333333" + inkscape:cx="450" + inkscape:cy="450" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + units="in" + inkscape:window-width="1600" + inkscape:window-height="868" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1"> + <inkscape:grid + type="xygrid" + id="grid2985" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <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 + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-152.3622)"> + <path + sodipodi:type="star" + style="fill:#4d4d4d;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + id="path2995" + sodipodi:sides="3" + sodipodi:cx="460" + sodipodi:cy="420" + sodipodi:r1="380.52594" + sodipodi:r2="190.26299" + sodipodi:arg1="0" + sodipodi:arg2="1.0471976" + inkscape:flatsided="true" + inkscape:rounded="0" + inkscape:randomized="0" + d="m 840.52594,420 -570.78891,329.54513 0,-659.090261 z" + transform="matrix(-1,0,0,-1,1014.9543,1026.7074)" + inkscape:transform-center-y="-2.9985352e-05" + inkscape:transform-center-x="95.131485" /> + </g> +</svg> diff --git a/src/mobile/qml/main.qml b/src/mobile/qml/main.qml new file mode 100644 index 0000000..d7597b1 --- /dev/null +++ b/src/mobile/qml/main.qml @@ -0,0 +1,270 @@ +import QtQuick 2.1 +import BibleTime 1.0 + +Rectangle { + id: root + + property int opacitypopup: 0 + property QtObject component: null; + property Item window: null; + + ListModel { + id: windowsModel + + ListElement { title: ""; action: "" } + } + + function installModules() { + installManager.openChooser(); + } + +// width: 1280 // Nexus 7 (2012) +// height: 800 + + width: 480 // Phone + height: 800 + + rotation: 0 + + MainToolbar { + id: mainToolbar + + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + height: 30 + onButtonClicked: { + mainMenus.visible = ! mainMenus.visible; + } + } + + Rectangle { + id: spacer + + anchors.top: mainToolbar.bottom + height:2 + width: parent.width + color: "#646464" + } + + WindowManager { + id: windowManager + + anchors.top: spacer.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + color: "#646464" + + } + + Settings { + id: settings + + visible: false; + } + + GridChooser { + id: gridChooser + + objectName: "gridChooser" + width: parent.width + height: parent.height + visible: false + } + + BtStyle { + id: btStyle + } + + ModuleChooser { + id: moduleChooser + + objectName: "moduleChooser" + visible: false + width: Math.min(parent.height, parent.width); + height: parent.height + anchors.centerIn: parent + } + + TreeChooser { + id: treeChooser + + objectName: "treeChooser" + width:480 + height: parent.height + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + path: "" + visible: false + z: 100 + } + + InstallManager { + id: installManager + } + + InstallManagerChooser { + id: installManagerChooser + + objectName: "installManagerChooser" + width: Math.min(parent.height, parent.width); + height: parent.height + anchors.centerIn: parent + anchors.top: parent.top + visible: false + } + + Progress { + id: progress + + objectName: "progress" + value: 0.25 + minimumValue: 0 + maximumValue: 1 + width:550 + height: 200 + anchors.centerIn: parent + anchors.top: parent.top + visible: false + } + + ListModel { + id: mainMenusModel + + ListElement { title: QT_TR_NOOP("New Window"); action: "newWindow" } + ListElement { title: QT_TR_NOOP("View Window"); action: "windows" } + ListElement { title: QT_TR_NOOP("Text Font Size"); action: "textFontSize"} + ListElement { title: QT_TR_NOOP("User Interface Font Size");action: "uiFontSize"} + + //ListElement { title: QT_TR_NOOP("Settings"); action: "settings" } + ListElement { title: QT_TR_NOOP("Bookshelf Manager"); action: "install" } + // ListElement { title: QT_TR_NOOP("Gnome Style"); action: "gnomeStyle" } + // ListElement { title: QT_TR_NOOP("Android Style"); action: "androidStyle" } + } + + Menus { + id: mainMenus + + Component.onCompleted: menuSelected.connect(mainMenus.doAction) + + function doAction(action) { + mainMenus.visible = false; + if (action == "newWindow") { + windowManager.newWindow(); + } + else if (action == "windows") { + windowManager.createWindowMenus(); + } + else if (action == "gnomeStyle") { + btStyle.setStyle(1) + } + else if (action == "androidStyle") { + btStyle.setStyle(2) + } + else if (action == "install") { + installModules(); + } + else if (action == "settings") { + settings.visible = true; + } + else if (action == "textFontSize") { + textFontPointSize.visible = true; + } + else if (action == "uiFontSize") { + uiFontPointSize.visible = true; + } + + } + + model: mainMenusModel + topMenuMargin: 100 + } + + ListModel { + id: windowArrangementModel + + ListElement { title: QT_TR_NOOP("Single"); action: "single" } + ListElement { title: QT_TR_NOOP("Tabbed"); action: "tabbed" } + ListElement { title: QT_TR_NOOP("Auto-tile"); action: "autoTile" } + ListElement { title: QT_TR_NOOP("Auto-tile horizontally"); action: "autoTileHor" } + ListElement { title: QT_TR_NOOP("Auto-tile vertically"); action: "autoTileVer" } + } + + Menus { + id: windowArrangementMenus + + Component.onCompleted: menuSelected.connect(windowArrangementMenus.doAction) + + function doAction(action) { + windowArrangementMenus.visible = false; + if (action == "single") { + windowManager.setWindowArrangement(windowManager.single); + } + else if (action == "tabbed") { + windowManager.setWindowArrangement(windowManager.tabLayout); + } + else if (action == "autoTile") { + windowManager.setWindowArrangement(windowManager.autoTile); + } + else if (action == "autoTileHor") { + windowManager.setWindowArrangement(windowManager.autoTileHor); + } + else if (action == "autoTileVer") { + windowManager.setWindowArrangement(windowManager.autoTileVer); + } + } + + model: windowArrangementModel + } + + Menus { + id: windowTitlesMenus + + model: windowsModel + visible: false + Component.onCompleted: menuSelected.connect(windowTitlesMenus.doAction) + + function doAction(action) { + windowTitlesMenus.visible = false; + var index = Number(action) + windowManager.setCurrentTabbedWindow(index); + } + } + + FontSizeSlider { + id: uiFontPointSize + visible: false + title: "User Interface Font Size" + + onVisibleChanged: { + if (visible) + { + uiFontPointSize.current = btStyle.uiFontPointSize; + uiFontPointSize.previous = btStyle.uiFontPointSize; + } + } + + onAccepted: { + btStyle.uiFontPointSize = pointSize + } + } + + FontSizeSlider { + id: textFontPointSize + visible: false + title: "Text Font Size" + + onVisibleChanged: { + if (visible) + { + textFontPointSize.current = btStyle.textFontPointSize; + textFontPointSize.previous = btStyle.textFontPointSize; + } + } + + onAccepted: { + btStyle.textFontPointSize = pointSize; + } + } +} diff --git a/src/mobile/qml/rightarrow.svg b/src/mobile/qml/rightarrow.svg new file mode 100644 index 0000000..e9fd5d1 --- /dev/null +++ b/src/mobile/qml/rightarrow.svg @@ -0,0 +1,82 @@ +<?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="900" + height="900" + id="svg2" + version="1.1" + inkscape:version="0.48.4 r9939" + sodipodi:docname="New document 1"> + <defs + id="defs4" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.49497475" + inkscape:cx="21.09998" + inkscape:cy="433.47351" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + units="in" + inkscape:window-width="1600" + inkscape:window-height="868" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1"> + <inkscape:grid + type="xygrid" + id="grid2985" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <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 + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-152.3622)"> + <path + sodipodi:type="star" + style="fill:#4d4d4d;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" + id="path2995" + sodipodi:sides="3" + sodipodi:cx="460" + sodipodi:cy="420" + sodipodi:r1="380.52594" + sodipodi:r2="190.26299" + sodipodi:arg1="0" + sodipodi:arg2="1.0471976" + inkscape:flatsided="true" + inkscape:rounded="0" + inkscape:randomized="0" + d="m 840.52594,420 -570.78891,329.54513 0,-659.090261 z" + transform="translate(-101.01525,164.48403)" + inkscape:transform-center-x="-95.131488" /> + </g> +</svg> diff --git a/src/mobile/qml/tab.png b/src/mobile/qml/tab.png Binary files differnew file mode 100644 index 0000000..ad80216 --- /dev/null +++ b/src/mobile/qml/tab.png diff --git a/src/mobile/ui/btstyle.cpp b/src/mobile/ui/btstyle.cpp new file mode 100644 index 0000000..ee22d15 --- /dev/null +++ b/src/mobile/ui/btstyle.cpp @@ -0,0 +1,334 @@ + +#include "btstyle.h" +#include <QList> +#include <QPointer> +#include "backend/config/btconfig.h" + +// BtStyle is a class that is registered at a QML item. It can be placed into +// QML files and its properties are available to be used in QML. It contains +// colors, sizes, etc. that affect the look of the UI. You can have multipe +// instances of the item. Changing a property on one of them changes all of them +/* + import BibleTime 1.0 + + BtStyle { + id: btStyle + } + + Rectangle { + color: btStyle.button + } +*/ + +namespace btm { + +// Only one copy of properties so they are the same everywhere used. +static QColor buttonColor = QColor(); +static QColor buttonBackground = QColor(); +static QColor buttonTextColor = QColor(); +static QColor buttonHighlightedText = QColor(); +static QColor buttonBorder = QColor(); +static int buttonRadius = 0; +static QColor buttonGradient0; +static QColor buttonGradient1; +static QColor buttonGradient2; +static QColor buttonGradient3; + +static QColor windowTab = QColor(); +static QColor windowTabSelected = QColor(); +static QColor windowTabText = QColor(); +static QColor windowTabTextSelected = QColor(); + +static QColor menu = QColor(); +static QColor menuBorder = QColor(); +static QColor menuText = QColor(); +static int menuHeight = 0; + +static QColor toolbarColor = QColor(); +static QColor toolbarButton = QColor(); +static QColor toolbarButtonText = QColor(); +static double toolbarTextPointSize = 6; + + +static QList<QPointer<BtStyle> > styles; + +static void emitChanged() { + for (int i=0; i<styles.count(); ++i) { + QPointer<BtStyle> style = styles.at(i); + if (style != 0) + style->changed(); + } +} + +void BtStyle::setStyle(int style) { + if (style == BtStyle::gnome) { + setButtonColor(QColor(0,0,0)); + setButtonBackground(QColor(237, 237, 237)); + setButtonTextColor(QColor(0,0,0)); + setButtonHighlightedText(QColor(0,0,255)); + setButtonBorder(QColor(80,80,0)); + setButtonRadius(3); + setButtonGradient0(QColor(200,200,200)); + setButtonGradient1(QColor(246,246,246)); + setButtonGradient2(QColor(246,246,246)); + setButtonGradient3(QColor(200,200,200)); + + setWindowTab(QColor(206,206,206)); + setWindowTabSelected(QColor(255,255,255)); + setWindowTabText(QColor(0,0,0)); + setWindowTabTextSelected(QColor(0,0,0)); + + setMenu(QColor(255,255,255)); + setMenuBorder(QColor(255,255,255)); + setMenuText(QColor(0,0,0)); + setMenuHeight(40); + + setToolbarColor(QColor(237,237,237)); + setToolbarButton(QColor(237,237,237)); + setToolbarButtonText(QColor(0,0,0)); + setToolbarTextPointSize(10); + } + else if (style == BtStyle::android) { + setButtonColor(QColor(0,0,0)); + setButtonBackground(QColor(35,35,100)); + setButtonTextColor(QColor(255,210,0)); + setButtonHighlightedText(QColor(255,255,0)); + setButtonBorder(QColor(80,80,0)); + setButtonRadius(3); + setButtonGradient0(QColor(125,125,125)); + setButtonGradient1(QColor(60,60,60)); + setButtonGradient2(QColor(50,50,50)); + setButtonGradient3(QColor(20,20,20)); + + setWindowTab(QColor(100,100,100)); + setWindowTabSelected(QColor(255,255,255)); + setWindowTabText(QColor(255,255,255)); + setWindowTabTextSelected(QColor(0,0,0)); + + setMenu(QColor(255,255,255)); + setMenuBorder(QColor(224,224,224)); + setMenuText(QColor(0,0,0)); + setMenuHeight(34); + + setToolbarColor(QColor(120,120,120)); + setToolbarButton(QColor(255,210,0)); + setToolbarButtonText(QColor(0,0,0)); + setToolbarTextPointSize(10); + } + + emitChanged(); +} + +BtStyle::BtStyle(QObject* parent) + : QObject(parent) { + styles.append(this); +} + +QColor BtStyle::getButtonColor() const { + return buttonColor; +} +void BtStyle::setButtonColor(const QColor& color) { + buttonColor = color; + emitChanged(); +} + + +QColor BtStyle::getButtonBackground() const { + return buttonBackground; +} +void BtStyle::setButtonBackground(const QColor& color) { + buttonBackground = color; + emitChanged(); +} + + +QColor BtStyle::getButtonTextColor() const { + return buttonTextColor; +} +void BtStyle::setButtonTextColor(const QColor& color) { + buttonTextColor = color; + emitChanged(); +} + + +QColor BtStyle::getButtonHighlightedText() const { + return buttonHighlightedText; +} +void BtStyle::setButtonHighlightedText(const QColor& color) { + buttonHighlightedText = color; + emitChanged(); +} + + +QColor BtStyle::getButtonBorder() const { + return buttonBorder; +} +void BtStyle::setButtonBorder(const QColor& color) { + buttonBorder = color; + emitChanged(); +} + +int BtStyle::getButtonRadius() const { + return buttonRadius; +} +void BtStyle::setButtonRadius(int radius) { + buttonRadius = radius; + emitChanged(); +} + +QColor BtStyle::getButtonGradient0() const { + return buttonGradient0; +} +void BtStyle::setButtonGradient0(const QColor& color) { + buttonGradient0 = color; + emitChanged(); +} + +QColor BtStyle::getButtonGradient1() const { + return buttonGradient1; +} +void BtStyle::setButtonGradient1(const QColor& color) { + buttonGradient1 = color; + emitChanged(); +} + +QColor BtStyle::getButtonGradient2() const { + return buttonGradient2; +} +void BtStyle::setButtonGradient2(const QColor& color) { + buttonGradient2 = color; + emitChanged(); +} + +QColor BtStyle::getButtonGradient3() const { + return buttonGradient3; +} +void BtStyle::setButtonGradient3(const QColor& color) { + buttonGradient3 = color; + emitChanged(); +} + +QColor BtStyle::getWindowTab() const { + return windowTab; +} + +void BtStyle::setWindowTab(const QColor& color) { + windowTab = color; + emitChanged(); +} + +QColor BtStyle::getWindowTabSelected() const { + return windowTabSelected; +} + +void BtStyle::setWindowTabSelected(const QColor& color) { + windowTabSelected = color; + emitChanged(); +} + +QColor BtStyle::getWindowTabText() const { + return windowTabText; +} + +void BtStyle::setWindowTabText(const QColor& color) { + windowTabText = color; + emitChanged(); +} + +QColor BtStyle::getWindowTabTextSelected() const { + return windowTabTextSelected; +} + +void BtStyle::setWindowTabTextSelected(const QColor& color) { + windowTabTextSelected = color; + emitChanged(); +} + +QColor BtStyle::getMenu() const { + return menu; +} + +void BtStyle::setMenu(const QColor& color) { + menu = color; + emitChanged(); +} + +QColor BtStyle::getMenuBorder() const { + return menuBorder; +} + +void BtStyle::setMenuBorder(const QColor& color) { + menuBorder = color; + emitChanged(); +} + +QColor BtStyle::getMenuText() const { + return menuText; +} + +void BtStyle::setMenuText(const QColor& color) { + menuText = color; + emitChanged(); +} + +int BtStyle::getMenuHeight() const { + return menuHeight; +} +void BtStyle::setMenuHeight(int height) { + menuHeight = height; + emitChanged(); +} + +QColor BtStyle::getToolbarColor() const { + return toolbarColor; +} +void BtStyle::setToolbarColor(const QColor& color) { + toolbarColor = color; + emitChanged(); +} + +QColor BtStyle::getToolbarButton() const { + return toolbarButton; +} +void BtStyle::setToolbarButton(const QColor& color) { + toolbarButton = color; + emitChanged(); +} + +QColor BtStyle::getToolbarButtonText() const { + return toolbarButtonText; +} +void BtStyle::setToolbarButtonText(const QColor& color) { + toolbarButtonText = color; + emitChanged(); +} + +double BtStyle::getToolbarTextPointSize() const { + return toolbarTextPointSize; +} + +void BtStyle::setToolbarTextPointSize(double pointSize) { + toolbarTextPointSize = pointSize; + emitChanged(); +} + +double BtStyle::getTextFontPointSize() const { + return btConfig().value<int>("ui/textFontSize",14); +} + +void BtStyle::setTextFontPointSize(double pointSize) { + btConfig().setValue<int>("ui/textFontSize", pointSize); + emitChanged(); +} + +double BtStyle::getUiFontPointSize() const { + return btConfig().value<int>("ui/uiFontSize",14); +} + +void BtStyle::setUiFontPointSize(double pointSize) { + btConfig().setValue<int>("ui/uiFontSize", pointSize); + emitChanged(); +} + +} // end namespace + diff --git a/src/mobile/ui/btstyle.h b/src/mobile/ui/btstyle.h new file mode 100644 index 0000000..7f65c22 --- /dev/null +++ b/src/mobile/ui/btstyle.h @@ -0,0 +1,132 @@ +#ifndef BT_STYLE_H +#define BT_STYLE_H + +#include <QObject> +#include <QColor> + +namespace btm { + +class BtStyle : public QObject { + Q_OBJECT + + Q_PROPERTY(QColor buttonColor READ getButtonColor NOTIFY changed) + Q_PROPERTY(QColor buttonBackground READ getButtonBackground NOTIFY changed) + Q_PROPERTY(QColor buttonTextColor READ getButtonTextColor NOTIFY changed) + Q_PROPERTY(QColor buttonHighlightedText READ getButtonHighlightedText NOTIFY changed) + Q_PROPERTY(QColor buttonBorder READ getButtonBorder NOTIFY changed) + Q_PROPERTY(int buttonRadius READ getButtonRadius NOTIFY changed) + + Q_PROPERTY(QColor buttonGradient0 READ getButtonGradient0 NOTIFY changed) + Q_PROPERTY(QColor buttonGradient1 READ getButtonGradient1 NOTIFY changed) + Q_PROPERTY(QColor buttonGradient2 READ getButtonGradient2 NOTIFY changed) + Q_PROPERTY(QColor buttonGradient3 READ getButtonGradient3 NOTIFY changed) + + + Q_PROPERTY(QColor windowTab READ getWindowTab NOTIFY changed) + Q_PROPERTY(QColor windowTabSelected READ getWindowTabSelected NOTIFY changed) + Q_PROPERTY(QColor windowTabText READ getWindowTabText NOTIFY changed) + Q_PROPERTY(QColor windowTabTextSelected READ getWindowTabTextSelected NOTIFY changed) + + Q_PROPERTY(QColor menu READ getMenu NOTIFY changed) + Q_PROPERTY(QColor menuBorder READ getMenuBorder NOTIFY changed) + Q_PROPERTY(QColor menuText READ getMenuText NOTIFY changed) + Q_PROPERTY(int menuHeight READ getMenuHeight() NOTIFY changed) + + Q_PROPERTY(QColor toolbarColor READ getToolbarColor NOTIFY changed) + Q_PROPERTY(QColor toolbarButton READ getToolbarButton NOTIFY changed) + Q_PROPERTY(QColor toolbarButtonText READ getToolbarButtonText NOTIFY changed) + Q_PROPERTY(double toolbarTextPointSize READ getToolbarTextPointSize NOTIFY changed); + + Q_PROPERTY(double textFontPointSize READ getTextFontPointSize WRITE setTextFontPointSize NOTIFY changed); + Q_PROPERTY(double uiFontPointSize READ getUiFontPointSize WRITE setUiFontPointSize NOTIFY changed); + +public: + Q_INVOKABLE void setStyle(int style); + + enum Style { + gnome = 1, + android = 2 + }; + + + BtStyle(QObject *parent = 0); + + QColor getButtonColor() const; + void setButtonColor(const QColor& color); + + QColor getButtonBackground() const; + void setButtonBackground(const QColor& color); + + QColor getButtonTextColor() const; + void setButtonTextColor(const QColor& color); + + QColor getButtonHighlightedText() const; + void setButtonHighlightedText(const QColor& color); + + QColor getButtonBorder() const; + void setButtonBorder(const QColor& color); + + int getButtonRadius() const; + void setButtonRadius(int radius); + + QColor getButtonGradient0() const; + void setButtonGradient0(const QColor& color); + + QColor getButtonGradient1() const; + void setButtonGradient1(const QColor& color); + + QColor getButtonGradient2() const; + void setButtonGradient2(const QColor& color); + + QColor getButtonGradient3() const; + void setButtonGradient3(const QColor& color); + + QColor getWindowTab() const; + void setWindowTab(const QColor& color); + + QColor getWindowTabSelected() const; + void setWindowTabSelected(const QColor& color); + + QColor getWindowTabText() const; + void setWindowTabText(const QColor& color); + + QColor getWindowTabTextSelected() const; + void setWindowTabTextSelected(const QColor& color); + + QColor getMenu() const; + void setMenu(const QColor& color); + + QColor getMenuBorder() const; + void setMenuBorder(const QColor& color); + + QColor getMenuText() const; + void setMenuText(const QColor& color); + + int getMenuHeight() const; + void setMenuHeight(int height); + + QColor getToolbarColor() const; + void setToolbarColor(const QColor& color); + + QColor getToolbarButton() const; + void setToolbarButton(const QColor& color); + + QColor getToolbarButtonText() const; + void setToolbarButtonText(const QColor& color); + + double getToolbarTextPointSize() const; + void setToolbarTextPointSize(double pointSize); + + double getTextFontPointSize() const; + void setTextFontPointSize(double pointSize); + + double getUiFontPointSize() const; + void setUiFontPointSize(double pointSize); + +signals: + void changed(); +}; + +} // end namespace + +#endif diff --git a/src/mobile/ui/btwindowinterface.cpp b/src/mobile/ui/btwindowinterface.cpp new file mode 100644 index 0000000..1016055 --- /dev/null +++ b/src/mobile/ui/btwindowinterface.cpp @@ -0,0 +1,257 @@ + +#include "btwindowinterface.h" + +#include "backend/config/btconfig.h" +#include "backend/drivers/cswordbiblemoduleinfo.h" +#include "backend/drivers/cswordmoduleinfo.h" +#include "backend/keys/cswordkey.h" +#include "backend/keys/cswordtreekey.h" +#include "backend/managers/cswordbackend.h" +#include "backend/rendering/centrydisplay.h" +#include "backend/rendering/cdisplayrendering.h" +#include "mobile/btmmain.h" +#include "mobile/keychooser/versechooser.h" +#include "mobile/keychooser/bookkeychooser.h" +#include "mobile/ui/modulechooser.h" +#include "mobile/ui/viewmanager.h" +#include <QDebug> +#include <QFile> +#include <QObject> +#include <QQmlContext> +#include <QQmlEngine> +#include <QQuickItem> +#include <QStringList> + + +namespace btm { + +BtWindowInterface::BtWindowInterface(QObject* parent) + : QObject(parent), + m_key(0), + m_textModel(new RoleItemModel()), + m_bookKeyChooser(0), + m_verseKeyChooser(0), + m_bibleTextModelBuilder(m_textModel), + m_bookTextModelBuilder(m_textModel){ + + QtQuick2ApplicationViewer* viewer = getViewManager()->getViewer(); + m_verseKeyChooser = new VerseChooser(viewer, this); + bool ok = connect(m_verseKeyChooser, SIGNAL(referenceChanged()), this, SLOT(referenceChanged())); + Q_ASSERT(ok); + + m_bookKeyChooser = new BookKeyChooser(viewer, this); + ok = connect(m_bookKeyChooser, SIGNAL(referenceChanged()), this, SLOT(referenceChanged())); + Q_ASSERT(ok); +} + +static QString getKeyText(CSwordKey* key) { + QString keyText; + if ( ! key) + return keyText; + + CSwordVerseKey* verseKey = dynamic_cast<CSwordVerseKey*>(key); + if (verseKey) { + keyText = verseKey->key(); + return keyText; + } + + CSwordTreeKey* treeKey = dynamic_cast<CSwordTreeKey*>(key); + if (treeKey) { + keyText = treeKey->key(); + return keyText; + } + return keyText; +} + +void BtWindowInterface::updateModel() { + QString moduleName= getModuleName(); + QStringList moduleList = QStringList() << moduleName; + QList<const CSwordModuleInfo*> modules = + CSwordBackend::instance()->getConstPointerList(moduleList); + QString keyText = getKeyText(m_key); + + m_textModel->clear(); + if (modules.at(0)->type() == CSwordModuleInfo::Bible) + m_bibleTextModelBuilder.updateModel(modules, keyText); + else if (modules.at(0)->type() == CSwordModuleInfo::GenericBook) + m_bookTextModelBuilder.updateModel(modules, keyText); + + emit currentModelIndexChanged(); +} + +int BtWindowInterface::getCurrentModelIndex() const { + return m_bibleTextModelBuilder.getCurrentModelIndex(); +} + +static bool moduleIsBibleOrCommentary(const CSwordModuleInfo* module) { + CSwordModuleInfo::Category category = module->category(); + if (category == CSwordModuleInfo::Bibles || + category == CSwordModuleInfo::Commentaries) + return true; + return false; +} + +static bool moduleIsBook(const CSwordModuleInfo* module) { + CSwordModuleInfo::Category category = module->category(); + if (category == CSwordModuleInfo::Books) + return true; + return false; +} + +QString BtWindowInterface::getModuleName() const { + QString moduleName; + if (m_key) + moduleName = m_key->module()->name(); + return moduleName; +} + +void BtWindowInterface::setModuleName(const QString& moduleName) { + CSwordModuleInfo* m = CSwordBackend::instance()->findModuleByName(moduleName); + if (!m_key) { + m_key = CSwordKey::createInstance(m); + } + else { + if (moduleIsBibleOrCommentary(m) && + moduleIsBibleOrCommentary(m_key->module())) { + m_key->setModule(m); + } + else if (moduleIsBook(m) && + moduleIsBook(m_key->module())) { + m_key->setModule(m); + } + + else { + delete m_key; + m_key = CSwordKey::createInstance(m); + } + + } + + CSwordTreeKey* treeKey = dynamic_cast<CSwordTreeKey*>(m_key); + if (treeKey) + treeKey->firstChild(); + + emit moduleChanged(); + emit referenceChange(); + updateModel(); +} + +QString BtWindowInterface::getReference() const { + QString reference; + if (m_key) + reference = m_key->key(); + return reference; +} + +void BtWindowInterface::changeModule() { + QtQuick2ApplicationViewer* viewer = getViewManager()->getViewer(); + ModuleChooser* dlg = new ModuleChooser(viewer, this); + dlg->open(); +} + +static void parseKey(CSwordTreeKey* currentKey, QStringList* keyPath, QStringList* children) +{ + if (currentKey == 0) + return; + + CSwordTreeKey localKey(*currentKey); + + QString oldKey = localKey.key(); //string backup of key + + if (oldKey.isEmpty()) { //don't set keys equal to "/", always use a key which may have content + localKey.firstChild(); + oldKey = localKey.key(); + } +// const int oldOffset = localKey.getOffset(); //backup key position + + QStringList siblings; //split up key + if (!oldKey.isEmpty()) { + siblings = oldKey.split('/', QString::SkipEmptyParts); + } + + int depth = 0; + int index = 0; + localKey.root(); //start iteration at root node + + while ( localKey.firstChild() && (depth < siblings.count()) ) { + QString key = localKey.key(); + index = (depth == 0) ? -1 : 0; + + bool found = false; + do { //look for matching sibling + ++index; + found = (localKey.getLocalNameUnicode() == siblings[depth]); + } + while (!found && localKey.nextSibling()); + + if (found) + key = localKey.key(); //found: change key to this level + else + localKey.setKey(key); //not found: restore old key + + *keyPath << key; + + //last iteration: get child entries + if (depth == siblings.count() - 1 && localKey.hasChildren()) { + localKey.firstChild(); + ++depth; + do { + *children << localKey.getLocalNameUnicode(); + } + while (localKey.nextSibling()); + } + depth++; + } +} + +void BtWindowInterface::changeReference() { + CSwordVerseKey* verseKey = dynamic_cast<CSwordVerseKey*>(m_key); + if (verseKey != 0) { + m_verseKeyChooser->open(verseKey); + } + + CSwordTreeKey* treeKey = dynamic_cast<CSwordTreeKey*>(m_key); + if (treeKey != 0) { + QStringList keyPath; + QStringList children; + parseKey(treeKey, &keyPath, &children); + m_bookKeyChooser->open(); + } +} + +void BtWindowInterface::referenceChanged() { + emit referenceChange(); + updateModel(); +} + +const CSwordModuleInfo* BtWindowInterface::module() const { + const CSwordModuleInfo* module = m_key->module(); + return module; +} + +CSwordKey* BtWindowInterface::getKey() const { + return m_key; +} + +int BtWindowInterface::getFontSize() const { + const CLanguageMgr::Language* lang = module()->language(); + BtConfig::FontSettingsPair fontPair = btConfig().getFontForLanguage(*lang); + QFont font = fontPair.second; + return font.pointSize(); +} + +void BtWindowInterface::setFontSize(int size) { + const CLanguageMgr::Language* lang = module()->language(); + BtConfig::FontSettingsPair fontPair = btConfig().getFontForLanguage(*lang); + fontPair.second.setPointSize(size); + btConfig().setFontForLanguage(*lang, fontPair); + emit textChanged(); +} + +QVariant BtWindowInterface::getTextModel() { + QVariant var; + var.setValue(m_textModel); + return var; +} + +} // end namespace diff --git a/src/mobile/ui/btwindowinterface.h b/src/mobile/ui/btwindowinterface.h new file mode 100644 index 0000000..c6c31b0 --- /dev/null +++ b/src/mobile/ui/btwindowinterface.h @@ -0,0 +1,73 @@ +#ifndef BT_WINDOW_INTERFACE_H +#define BT_WINDOW_INTERFACE_H + +#include <QObject> +#include <QString> +#include "mobile/models/roleitemmodel.h" +#include "mobile/models/bibletextmodelbuilder.h" +#include "mobile/models/booktextmodelbuilder.h" + +class CSwordKey; +class CSwordVerseKey; +class CSwordModuleInfo; + +namespace btm { + +class BookKeyChooser; +class VerseChooser; + +class BtWindowInterface : public QObject { + + Q_OBJECT + + Q_PROPERTY(QString moduleName READ getModuleName WRITE setModuleName NOTIFY moduleChanged) + Q_PROPERTY(QString reference READ getReference NOTIFY referenceChange) + Q_PROPERTY(int fontSize READ getFontSize WRITE setFontSize NOTIFY textChanged) + Q_PROPERTY(QVariant textModel READ getTextModel NOTIFY textModelChanged) + Q_PROPERTY(int currentModelIndex READ getCurrentModelIndex NOTIFY currentModelIndexChanged) + +public: + Q_INVOKABLE void changeModule(); + Q_INVOKABLE void changeReference(); + + BtWindowInterface(QObject *parent = 0); + + CSwordKey* getKey() const; + + QString getModuleName() const; + void setModuleName(const QString& moduleName); + + QString getReference() const; + + int getCurrentModelIndex() const; + + int getFontSize() const; + void setFontSize(int size); + + QVariant getTextModel(); + +signals: + void referenceChange(); + void moduleChanged(); + void textChanged(); + void textModelChanged(); + void currentModelIndexChanged(); + +private slots: + void referenceChanged(); + +private: + const CSwordModuleInfo* module() const; + void updateModel(); + + CSwordKey* m_key; + RoleItemModel* m_textModel; + BookKeyChooser* m_bookKeyChooser; + VerseChooser* m_verseKeyChooser; + BibleTextModelBuilder m_bibleTextModelBuilder; + BookTextModelBuilder m_bookTextModelBuilder; +}; + +} // end namespace + +#endif diff --git a/src/mobile/ui/gridchooser.cpp b/src/mobile/ui/gridchooser.cpp new file mode 100644 index 0000000..3836b18 --- /dev/null +++ b/src/mobile/ui/gridchooser.cpp @@ -0,0 +1,63 @@ + +#include "gridchooser.h" + +#include "qtquick2applicationviewer.h" + +#include <algorithm> +#include <cmath> +#include <QEventLoop> +#include <QQuickItem> +#include <QQmlContext> +#include <QDebug> +#include <QCoreApplication> + +namespace btm { + +GridChooser::GridChooser(QtQuick2ApplicationViewer* viewer) + : viewer_(viewer), + gridChooserObject_(0) { + QQuickItem * rootObject = viewer_->rootObject(); + if (rootObject != 0) + gridChooserObject_ = rootObject->findChild<QQuickItem*>("gridChooser"); +} + +GridChooser::~GridChooser() { +} + +void GridChooser::open(const QStringList& stringList, const QString& highlight, const QString& title) { + Q_ASSERT(gridChooserObject_ != 0); + if (gridChooserObject_ == 0) + return; + + gridChooserObject_->disconnect(); + bool ok = connect(gridChooserObject_, SIGNAL(accepted(QString)), + this, SLOT(gridChooserAccepted(QString))); + Q_ASSERT(ok); + setProperties(stringList, highlight, title); +} + +void GridChooser::setProperties(const QStringList& list, const QString& hightlight, const QString& title) { + QQmlContext* ctx = viewer_->rootContext(); + ctx->setContextProperty("gridChooserModel",list); + gridChooserObject_->setProperty("selected",hightlight); + gridChooserObject_->setProperty("titleText",title); + + int maxLength = 0; + for (int i = 0; i < list.count(); ++i) { + QString text = list.at(i); + maxLength = std::max(maxLength, text.length()); + } + gridChooserObject_->setProperty("maxLength", maxLength); + + gridChooserObject_->setProperty("visible",true); +} + +void GridChooser::gridChooserAccepted(QString value) { + emit accepted(value); +} + +void GridChooser::gridChooserCanceled() { + emit canceled(); +} + +} // end namespace diff --git a/src/mobile/ui/gridchooser.h b/src/mobile/ui/gridchooser.h new file mode 100644 index 0000000..8200f91 --- /dev/null +++ b/src/mobile/ui/gridchooser.h @@ -0,0 +1,43 @@ +#ifndef GRID_CHOOSER_H +#define GRID_CHOOSER_H + +#include <QEventLoop> +#include <QObject> +#include <QList> + +class QtQuick2ApplicationViewer; +class QQuickItem; +class QStringList; +class QEventLoop; + +namespace btm { + +class BtWindowInterface; + +class GridChooser : public QObject { + Q_OBJECT + +public: + GridChooser(QtQuick2ApplicationViewer* viewer); + ~GridChooser(); + void open(const QStringList& stringList, const QString& highlight = QString(), const QString& title = QString()); + +signals: + void accepted(const QString& value); + void canceled(); + +private slots: + void gridChooserAccepted(QString value); + void gridChooserCanceled(); + +private: + void setProperties(const QStringList& list, const QString& hightlight, const QString& title); + + QtQuick2ApplicationViewer* viewer_; + QQuickItem* gridChooserObject_; + QEventLoop eventLoop_; +}; + +} // end namespace + +#endif diff --git a/src/mobile/ui/modulechooser.cpp b/src/mobile/ui/modulechooser.cpp new file mode 100644 index 0000000..bc3d582 --- /dev/null +++ b/src/mobile/ui/modulechooser.cpp @@ -0,0 +1,44 @@ + +#include "modulechooser.h" + +#include "qtquick2applicationviewer.h" + +#include "backend/bookshelfmodel/btbookshelftreemodel.h" +#include "backend/managers/cswordbackend.h" +#include <cmath> +#include <QQuickItem> +#include <QQmlProperty> +#include "btwindowinterface.h" +#include "mobile/util/findqmlobject.h" + +namespace btm { + +ModuleChooser::ModuleChooser(QtQuick2ApplicationViewer* viewer, BtWindowInterface* bibleVerse) + : viewer_(viewer), + bibleVerse_(bibleVerse) { +} + +void ModuleChooser::open() { + QQuickItem* item = findQmlObject("moduleChooser"); + Q_ASSERT(item != 0); + if (item == 0) + return; + + item->setProperty("visible", true); + bool ok = connect(item, SIGNAL(moduleSelected()), this, SLOT(moduleSelectedSlot())); + Q_ASSERT(ok); +} + +void ModuleChooser::moduleSelectedSlot() { + QQuickItem* item = findQmlObject("moduleChooser"); + Q_ASSERT(item != 0); + if (item == 0) + return; + + item->setProperty("visible", false); + QVariant v = item->property("selectedModule"); + QString moduleName = v.toString(); + bibleVerse_->setModuleName(moduleName); +} + +} // end namespace diff --git a/src/mobile/ui/modulechooser.h b/src/mobile/ui/modulechooser.h new file mode 100644 index 0000000..4e261f9 --- /dev/null +++ b/src/mobile/ui/modulechooser.h @@ -0,0 +1,35 @@ +#ifndef MODULE_CHOOSER_H +#define MODULE_CHOOSER_H + +#include <QObject> + +class QtQuick2ApplicationViewer; +class QStringList; + +namespace btm { + +class GridChooser; + +class BtWindowInterface; + +class ModuleChooser : public QObject { + Q_OBJECT + +public: + ModuleChooser(QtQuick2ApplicationViewer* viewer, BtWindowInterface* bibleVerse); + void open(); + +private slots: + void moduleSelectedSlot(); + +private: + void showGridChooser(const QStringList& list); + void setProperties(const QStringList& list); + + QtQuick2ApplicationViewer* viewer_; + BtWindowInterface* bibleVerse_; +}; + +} // end namespace + +#endif diff --git a/src/mobile/ui/moduleinterface.cpp b/src/mobile/ui/moduleinterface.cpp new file mode 100644 index 0000000..4d898b4 --- /dev/null +++ b/src/mobile/ui/moduleinterface.cpp @@ -0,0 +1,187 @@ + +#include "moduleinterface.h" + +#include "qtquick2applicationviewer.h" + +#include "backend/bookshelfmodel/btbookshelftreemodel.h" +#include "backend/managers/cswordbackend.h" +#include "mobile/util/findqmlobject.h" +#include <cmath> +#include <QQuickItem> +#include <QQmlProperty> +#include <QQmlContext> +#include <QDebug> +#include <QQmlProperty> +#include <QCoreApplication> +#include "btwindowinterface.h" +#include "gridchooser.h" + +namespace btm { + +ModuleInterface::ModuleInterface() { +} + +enum TextRoles { + TextRole = Qt::UserRole + 1 +}; + +typedef BtBookshelfModel::ModuleRole MRole; +static const MRole HR(BtBookshelfModel::ModuleHiddenRole); +static const MRole PR(BtBookshelfModel::ModulePointerRole); +static const MRole IR(BtBookshelfModel::ModuleHasIndexRole); +static const MRole CR(BtBookshelfModel::ModuleCategoryRole); + +static void setupTextModel(const QSet<QString>& modelSet, RoleItemModel* model) { + + QHash<int, QByteArray> roleNames; + roleNames[TextRole] = "modelText"; + model->setRoleNames(roleNames); + + QStringList modelList = modelSet.toList(); + modelList.sort(); + + model->clear(); + for (int i=0; i< modelList.count(); ++i) { + QString source = modelList.at(i); + QStandardItem* item = new QStandardItem(); + item->setData(source, TextRole); + model->appendRow(item); + } +} + +static CSwordModuleInfo* getModule(BtBookshelfModel* bookshelfModel, const QModelIndex& index) { + QVariant var = bookshelfModel->data(index, PR); + CSwordModuleInfo* module = static_cast<CSwordModuleInfo*>(var.value<void*>()); + return module; +} + +void ModuleInterface::updateCategoryAndLanguageModels() { + QQuickItem* object = findQmlObject("moduleChooser"); + if (object == 0) + return; + + getCategoriesAndLanguages(); + setupTextModel(m_categories, &m_categoryModel); + setupTextModel(m_languages, &m_languageModel); + object->setProperty("categoryModel", QVariant::fromValue(&m_categoryModel)); + object->setProperty("languageModel", QVariant::fromValue(&m_languageModel)); +} + +void ModuleInterface::getCategoriesAndLanguages() { + + m_categories.clear(); + m_languages.clear(); + + QQuickItem* object = findQmlObject("moduleChooser"); + if (object == 0) + return; + + BtBookshelfModel* bookshelfModel = CSwordBackend::instance()->model(); + if (bookshelfModel == 0) + return; + int count = bookshelfModel->rowCount(); + for (int row=0; row<count; ++row) { + QModelIndex index = bookshelfModel->index(row); + CSwordModuleInfo* module = getModule(bookshelfModel, index); + CSwordModuleInfo::Category category = module->category(); + QString categoryName = module->categoryName(category); + const CLanguageMgr::Language* language = module->language(); + QString languageName = language->translatedName(); + m_categories.insert(categoryName); + m_languages.insert(languageName); + } +} + +void ModuleInterface::updateWorksModel() { + m_worksModel.clear(); + m_modules.clear(); + + QString currentLang = currentLanguage(); + QString currentCat = currentCategory(); + + QHash<int, QByteArray> roleNames; + roleNames[TextRole] = "modelText"; + m_worksModel.setRoleNames(roleNames); + + BtBookshelfModel* bookshelfModel = CSwordBackend::instance()->model(); + if (bookshelfModel == 0) + return; + int count = bookshelfModel->rowCount(); + for (int row=0; row<count; ++row) { + QModelIndex index = bookshelfModel->index(row); + CSwordModuleInfo* module = getModule(bookshelfModel, index); + CSwordModuleInfo::Category category = module->category(); + QString categoryName = module->categoryName(category); + const CLanguageMgr::Language* language = module->language(); + QString languageName = language->translatedName(); + if (languageName == currentLang && + categoryName == currentCat) { + m_modules << module; + QString moduleName = module->name(); + QStandardItem* item = new QStandardItem(); + item->setData(moduleName, TextRole); + m_worksModel.appendRow(item); + } + } + + QQuickItem* object = findQmlObject("moduleChooser"); + if (object == 0) + return; + object->setProperty("worksModel", QVariant::fromValue(&m_worksModel)); +} + +QString ModuleInterface::currentLanguage() const { + QQuickItem* object = findQmlObject("moduleChooser"); + if (object == 0) + return ""; + int row = object->property("languageIndex").toInt(); + QModelIndex modelIndex = m_languageModel.index(row,0); + QString language = modelIndex.data(TextRole).toString(); + return language; + +} + +QString ModuleInterface::currentCategory() const { + QQuickItem* object = findQmlObject("moduleChooser"); + if (object == 0) + return ""; + int row = object->property("categoryIndex").toInt(); + QModelIndex modelIndex = m_categoryModel.index(row,0); + QString category = modelIndex.data(TextRole).toString(); + return category; +} + +QString ModuleInterface::category(int index) { + if (index < 0 || index >= m_modules.count()) + return ""; + CSwordModuleInfo* module = m_modules.at(index); + if (module == 0) + return ""; + CSwordModuleInfo::Category category = module->category(); + if (category == 0) + return ""; + return module->categoryName(category); +} + +QString ModuleInterface::language(int index) { + if (index < 0 || index >= m_modules.count()) + return ""; + CSwordModuleInfo* module = m_modules.at(index); + if (module == 0) + return ""; + const CLanguageMgr::Language* language = module->language(); + if (language == 0) + return ""; + return language->translatedName(); +} + +QString ModuleInterface::module(int index) { + if (index < 0 || index >= m_modules.count()) + return ""; + CSwordModuleInfo* module = m_modules.at(index); + if (module == 0) + return ""; + return module->name(); +} + +} // end namespace diff --git a/src/mobile/ui/moduleinterface.h b/src/mobile/ui/moduleinterface.h new file mode 100644 index 0000000..165c30f --- /dev/null +++ b/src/mobile/ui/moduleinterface.h @@ -0,0 +1,48 @@ +#ifndef MODULE_INTERFACE_H +#define MODULE_INTERFACE_H + +#include "mobile/models/roleitemmodel.h" +#include <QObject> +#include <QList> +#include <QSet> +#include <QString> + +class QQuickItem; +class QStringList; +class CSwordModuleInfo; + +namespace btm { + +class GridChooser; + +class BtWindowInterface; + +class ModuleInterface : public QObject { + Q_OBJECT + +public: + ModuleInterface(); + Q_INVOKABLE void updateCategoryAndLanguageModels(); + Q_INVOKABLE void updateWorksModel(); + Q_INVOKABLE QString category(int index); + Q_INVOKABLE QString language(int index); + Q_INVOKABLE QString module(int index); + +private: + void getCategoriesAndLanguages(); + void setProperties(const QStringList& list); + QString currentLanguage() const; + QString currentCategory() const; + + QSet<QString> m_categories; + QSet<QString> m_languages; + RoleItemModel m_categoryModel; + RoleItemModel m_languageModel; + RoleItemModel m_worksModel; + QList<CSwordModuleInfo*> m_modules; + +}; + +} // end namespace + +#endif diff --git a/src/mobile/ui/qtquick2applicationviewer.cpp b/src/mobile/ui/qtquick2applicationviewer.cpp new file mode 100644 index 0000000..b6077d8 --- /dev/null +++ b/src/mobile/ui/qtquick2applicationviewer.cpp @@ -0,0 +1,63 @@ +// checksum 0x56a9 version 0x80001 +/* + This file was generated by the Qt Quick 2 Application wizard of Qt Creator. + QtQuick2ApplicationViewer is a convenience class containing mobile device specific + code such as screen orientation handling. Also QML paths and debugging are + handled here. + It is recommended not to modify this file, since newer versions of Qt Creator + may offer an updated version of it. +*/ + +#include "qtquick2applicationviewer.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtQml/QQmlEngine> + +class QtQuick2ApplicationViewerPrivate { + QString mainQmlFile; + friend class QtQuick2ApplicationViewer; + static QString adjustPath(const QString &path); +}; + +QString QtQuick2ApplicationViewerPrivate::adjustPath(const QString &path) { +#if defined(Q_OS_MAC) + if (!QDir::isAbsolutePath(path)) + return QString::fromLatin1("%1/../Resources/%2") + .arg(QCoreApplication::applicationDirPath(), path); +#elif defined(Q_OS_UNIX) + const QString pathInInstallDir = + QString::fromLatin1("%1/../%2").arg(QCoreApplication::applicationDirPath(), path); + if (QFileInfo(pathInInstallDir).exists()) + return pathInInstallDir; +#endif + return path; +} + +QtQuick2ApplicationViewer::QtQuick2ApplicationViewer(QWindow *parent) + : QQuickView(parent) + , d(new QtQuick2ApplicationViewerPrivate()) { + connect(engine(), SIGNAL(quit()), SLOT(close())); + setResizeMode(QQuickView::SizeRootObjectToView); +} + +QtQuick2ApplicationViewer::~QtQuick2ApplicationViewer() { + delete d; +} + +void QtQuick2ApplicationViewer::setMainQmlFile(const QString &file) { + d->mainQmlFile = QtQuick2ApplicationViewerPrivate::adjustPath(file); + setSource(QUrl::fromLocalFile(d->mainQmlFile)); +} + +void QtQuick2ApplicationViewer::addImportPath(const QString &path) { + engine()->addImportPath(QtQuick2ApplicationViewerPrivate::adjustPath(path)); +} + +void QtQuick2ApplicationViewer::showExpanded() { +#if defined(Q_WS_SIMULATOR) + showFullScreen(); +#else + show(); +#endif +} diff --git a/src/mobile/ui/qtquick2applicationviewer.h b/src/mobile/ui/qtquick2applicationviewer.h new file mode 100644 index 0000000..a3db59d --- /dev/null +++ b/src/mobile/ui/qtquick2applicationviewer.h @@ -0,0 +1,32 @@ +// checksum 0xfde6 version 0x80001 +/* + This file was generated by the Qt Quick 2 Application wizard of Qt Creator. + QtQuick2ApplicationViewer is a convenience class containing mobile device specific + code such as screen orientation handling. Also QML paths and debugging are + handled here. + It is recommended not to modify this file, since newer versions of Qt Creator + may offer an updated version of it. +*/ + +#ifndef QTQUICK2APPLICATIONVIEWER_H +#define QTQUICK2APPLICATIONVIEWER_H + +#include <QtQuick/QQuickView> + +class QtQuick2ApplicationViewer : public QQuickView { + Q_OBJECT + +public: + explicit QtQuick2ApplicationViewer(QWindow *parent = 0); + virtual ~QtQuick2ApplicationViewer(); + + void setMainQmlFile(const QString &file); + void addImportPath(const QString &path); + + void showExpanded(); + +private: + class QtQuick2ApplicationViewerPrivate *d; +}; + +#endif // QTQUICK2APPLICATIONVIEWER_H diff --git a/src/mobile/ui/treechoosermodel.cpp b/src/mobile/ui/treechoosermodel.cpp new file mode 100644 index 0000000..cc5e2a7 --- /dev/null +++ b/src/mobile/ui/treechoosermodel.cpp @@ -0,0 +1,22 @@ + +#include "treechoosermodel.h" + + +TreeChooserModel::TreeChooserModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +QHash<int, QByteArray> TreeChooserModel::roleNames() const { + QHash<int, QByteArray> roles; + roles[NameRole] = "name"; + roles[ChildCountRole] = "childCount"; + return roles; +} + +void TreeChooserModel::addEntry(const QString& name, int childCount) { + int count = rowCount(); + beginInsertRows(count, count); + insertRow(count); + endInsertRows(); +} diff --git a/src/mobile/ui/treechoosermodel.h b/src/mobile/ui/treechoosermodel.h new file mode 100644 index 0000000..c1575ae --- /dev/null +++ b/src/mobile/ui/treechoosermodel.h @@ -0,0 +1,20 @@ +#ifndef TREE_CHOOSER_MODEL_H +#define TREE_CHOOSER_MODEL_H + +#include <QAbstractItemModel> + +class TreeChooserModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum TreeEntryRoles { + NameRole = Qt::UserRole + 1, + ChildCountRole + }; + + TreeChooserModel(QObject *parent = 0); + QHash<int, QByteArray> TreeChooserModel::roleNames() const; + +}; + +#endif diff --git a/src/mobile/ui/viewmanager.cpp b/src/mobile/ui/viewmanager.cpp new file mode 100644 index 0000000..041699a --- /dev/null +++ b/src/mobile/ui/viewmanager.cpp @@ -0,0 +1,52 @@ + +#include "viewmanager.h" + +#include "qtquick2applicationviewer.h" + +#include "btstyle.h" +#include <cmath> +#include <QGuiApplication> +#include <QJsonValue> +#include <QQuickItem> +#include <QQmlProperty> +#include <QQmlContext> +#include <QUrl> +#include <QDebug> + +namespace btm { + +static QString qmlFilePath(const QString& parentName, const QString& fileName) { + QString filePath = QCoreApplication::applicationDirPath() + "/../share/"; + filePath += parentName + "/"; + filePath += fileName; + return filePath; +} + +ViewManager::ViewManager() + : viewer_(new QtQuick2ApplicationViewer()) { + BtStyle style; + style.setStyle(BtStyle::gnome); + initialize_string_list_chooser_model(); + initialize_main_qml(); +} + +void ViewManager::initialize_string_list_chooser_model() { + QQmlContext* ctx = viewer_->rootContext(); + QStringList list = QStringList(); + ctx->setContextProperty("gridChooserModel",list); +} + +void ViewManager::initialize_main_qml() { + QString mainQml = qmlFilePath("qml", "main.qml"); + viewer_->setMainQmlFile(mainQml); +} + +void ViewManager::show() { + viewer_->showExpanded(); +} + +QtQuick2ApplicationViewer* ViewManager::getViewer() const { + return viewer_; +} + +} // end namespace diff --git a/src/mobile/ui/viewmanager.h b/src/mobile/ui/viewmanager.h new file mode 100644 index 0000000..7c50d35 --- /dev/null +++ b/src/mobile/ui/viewmanager.h @@ -0,0 +1,34 @@ +#ifndef VIEW_MANAGER_H +#define VIEW_MANAGER_H + +#include <QObject> +#include <QList> + +class QtQuick2ApplicationViewer; +class QStringList; + +namespace btm { +class BtWindowInterface; +} + +namespace btm { + +class ViewManager : public QObject { + Q_OBJECT + +public: + ViewManager(); + + void show(); + QtQuick2ApplicationViewer* getViewer() const; + +private: + void initialize_main_qml(); + void initialize_string_list_chooser_model(); + + QtQuick2ApplicationViewer* viewer_; +}; + +} // end namespace + +#endif diff --git a/src/mobile/util/findqmlobject.cpp b/src/mobile/util/findqmlobject.cpp new file mode 100644 index 0000000..25a317c --- /dev/null +++ b/src/mobile/util/findqmlobject.cpp @@ -0,0 +1,34 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#include "mobile/util/findqmlobject.h" +#include <QQuickItem> +#include "mobile/btmmain.h" +#include "mobile/ui/qtquick2applicationviewer.h" +#include "mobile/ui/viewmanager.h" + +namespace btm { + +QQuickItem* findQmlObject(const QString& objectName) { + + QtQuick2ApplicationViewer* viewer = getViewManager()->getViewer(); + QQuickItem * rootObject = 0; + if (viewer != 0) + rootObject = viewer->rootObject(); + QQuickItem* object = 0; + if (rootObject != 0) + object = rootObject->findChild<QQuickItem*>(objectName); + Q_ASSERT(object != 0); + return object; +} + +} diff --git a/src/mobile/util/findqmlobject.h b/src/mobile/util/findqmlobject.h new file mode 100644 index 0000000..bfbbcac --- /dev/null +++ b/src/mobile/util/findqmlobject.h @@ -0,0 +1,28 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License +* version 2.0. +* +**********/ + +#ifndef FIND_QML_OBJECT +#define FIND_QML_OBJECT + +#include <QString> + +class QQuickItem; + +namespace btm { + +// Finds the named QML object that is located at the +// top level of the QML objects. +QQuickItem* findQmlObject(const QString& objectName); + +} + +#endif diff --git a/src/mobile/util/messagedialog.cpp b/src/mobile/util/messagedialog.cpp new file mode 100644 index 0000000..a68857a --- /dev/null +++ b/src/mobile/util/messagedialog.cpp @@ -0,0 +1,36 @@ +/********* +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#include "messagedialog.h" + +#include <QMessageBox> +#include <QString> + + +namespace message { + +int showWarning(QWidget * /*parent*/, + const QString & /*title*/, + const QString & /*text*/, + QMessageBox::StandardButtons /*buttons*/, + QMessageBox::StandardButton /*defaultButton*/) { + // TODO - implement showWarning + return 0; +} + +int showQuestion(QWidget * /*parent*/, + const QString & /*title*/, + const QString & /*text*/, + QMessageBox::StandardButtons /*buttons*/, + QMessageBox::StandardButton /*defaultButton*/) { + // TODO - implement showQuestion + return 0; +} + +} // namespace message diff --git a/src/mobile/util/messagedialog.h b/src/mobile/util/messagedialog.h new file mode 100644 index 0000000..d56b9ea --- /dev/null +++ b/src/mobile/util/messagedialog.h @@ -0,0 +1,36 @@ +/********* +* +* In the name of the Father, and of the Son, and of the Holy Spirit. +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#ifndef UTIL_DIALOG_UTIL_H +#define UTIL_DIALOG_UTIL_H + +#include <QString> +#include <QMessageBox> + +class QWidget; + +namespace message { + +int showWarning(QWidget * parent, + const QString & title, + const QString & text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + +int showQuestion(QWidget * parent, + const QString & title, + const QString & text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + +} // namespace message + +#endif |