Verified Commit 7f55a3a8 authored by Jonah Brüchert's avatar Jonah Brüchert 🌳

Use json file based storage

* Allows to store isMobile again
parent 30db8cee
......@@ -21,5 +21,5 @@ ecm_add_test(browsermanagertest.cpp ../src/browsermanager.cpp ../src/urlmodel.cp
ecm_add_test(tabsmodeltest.cpp ../src/tabsmodel.cpp ../src/browsermanager.cpp ../src/urlmodel.cpp
TEST_NAME tabsmodeltest
LINK_LIBRARIES Qt5::Test
LINK_LIBRARIES Qt5::Test
)
......@@ -36,14 +36,15 @@ private Q_SLOTS:
// Current tab should be initial tab
QCOMPARE(m_tabsModel->currentTab(), 0);
QCOMPARE(m_tabsModel->tabs().at(0), "about:blank");
QCOMPARE(m_tabsModel->tab(0), TabState("about:blank", false));
}
void testNewTab()
{
m_tabsModel->newTab("https://kde.org");
QCOMPARE(m_tabsModel->tabs().count(), 2);
QCOMPARE(m_tabsModel->tabs().at(1), "https://kde.org");
qDebug() << m_tabsModel->tab(1).url() << m_tabsModel->tab(0).isMobile();
QCOMPARE(m_tabsModel->tab(1), TabState("https://kde.org", false));
// newly created tab should be current tab now
QCOMPARE(m_tabsModel->currentTab(), 1);
......@@ -51,7 +52,7 @@ private Q_SLOTS:
void testCurrentTab()
{
QCOMPARE(m_tabsModel->tabs().at(m_tabsModel->currentTab()), "https://kde.org");
QCOMPARE(m_tabsModel->tabs().at(m_tabsModel->currentTab()), TabState("https://kde.org", false));
}
void testCloseTab() {
......@@ -60,7 +61,7 @@ private Q_SLOTS:
QCOMPARE(m_tabsModel->tabs().count(), 1);
// Check tabs moved properly
QCOMPARE(m_tabsModel->tabs().at(0), "https://kde.org");
QCOMPARE(m_tabsModel->tabs().at(0), TabState("https://kde.org", false));
}
void testLoad() {
......@@ -69,7 +70,7 @@ private Q_SLOTS:
// Number of tabs must not change
QCOMPARE(m_tabsModel->tabs().count(), 1);
QCOMPARE(m_tabsModel->tabs().at(0), "https://debian.org");
QCOMPARE(m_tabsModel->tabs().at(0), TabState("https://debian.org", false));
}
void testRowCountMatches() {
......@@ -86,7 +87,7 @@ private Q_SLOTS:
// Check whether a new empty tab was created (count must not be less than one)
QCOMPARE(m_tabsModel->tabs().count(), 1);
QCOMPARE(m_tabsModel->tabs().at(0), "about:blank");
QCOMPARE(m_tabsModel->tabs().at(0), TabState("about:blank", false));
//
// Case 2: There are multiple tabs
......@@ -94,7 +95,7 @@ private Q_SLOTS:
m_tabsModel->newTab("second");
m_tabsModel->newTab("third");
QCOMPARE(m_tabsModel->tabs(), QStringList({"about:blank", "second", "third"}));
QCOMPARE(m_tabsModel->tabs(), QVector<TabState>({TabState("about:blank", false), TabState("second", false), TabState("third", false)}));
// current tab is 2
// close tab "second"
......@@ -103,12 +104,12 @@ private Q_SLOTS:
QCOMPARE(m_tabsModel->currentTab(), 0);
// "second" is indeed gone
QCOMPARE(m_tabsModel->tabs(), QStringList({"about:blank", "third"}));
QCOMPARE(m_tabsModel->tabs(), QVector<TabState>({TabState("about:blank", false), TabState("third", false)}));
}
void testSetTab() {
m_tabsModel->setTabUrl(0, "https://debian.org");
QCOMPARE(m_tabsModel->tabs(), QStringList({"https://debian.org", "third"}));
m_tabsModel->setTab(0, QLatin1String("https://debian.org"));
QCOMPARE(m_tabsModel->tabs(), QVector<TabState>({TabState("https://debian.org", false), TabState("third", false)}));
}
void testPrivateMode() {
......
......@@ -65,12 +65,12 @@ Repeater {
}
}
onUrlChanged: {
tabs.tabsModel.setTabUrl(index, url)
tabs.tabsModel.setTab(index, url)
}
}
Component.onCompleted: {
if (!privateTabsMode && !initialUrl && tabsModel.rowCount() === 1 && tabsModel.tabs[0] === "about:blank")
if (!privateTabsMode && !initialUrl && tabsModel.rowCount() === 1 && tabsModel.tabUrl(0) === "about:blank")
tabsModel.load(BrowserManager.homepage);
else if (initialUrl) {
tabsModel.newTab(initialUrl)
......
......@@ -295,6 +295,7 @@ Kirigami.ApplicationWindow {
currentWebView.userAgent.isMobile = true
}
currentWebView.reload()
tabs.tabsModel.setTab(tabs.tabsModel.currentTab)
}
}
]
......
......@@ -20,23 +20,23 @@
#include <QDebug>
#include <QUrl>
#include <QStandardPaths>
#include <QFile>
#include <QJsonDocument>
#include <QDir>
#include "browsermanager.h"
TabsModel::TabsModel(QObject *parent) : QAbstractListModel(parent) {
// We can only do this once we know whether we are in private mode or not
connect(this, &TabsModel::privateModeChanged, [&] {
if (!m_privateMode) {
loadTabs();
}
loadTabs();
});
connect(this, &TabsModel::currentTabChanged, [this] {
qDebug() << "Current tab changed to" << m_currentTab;
});
m_settings = AngelFish::BrowserManager::instance()->settings();
// Make sure model always contains at least one tab
createEmptyTab();
}
......@@ -44,7 +44,8 @@ TabsModel::TabsModel(QObject *parent) : QAbstractListModel(parent) {
QHash<int, QByteArray> TabsModel::roleNames() const
{
return {
{ RoleNames::UrlRole, QByteArrayLiteral("pageurl") }
{ RoleNames::UrlRole, QByteArrayLiteral("pageurl") },
{ RoleNames::IsMobileRole, QByteArrayLiteral("isMobile") }
};
}
......@@ -56,7 +57,9 @@ QVariant TabsModel::data(const QModelIndex &index, int role) const
switch(role) {
case RoleNames::UrlRole:
return QUrl(m_tabs.at(index.row()));
return m_tabs.at(index.row()).url();
case RoleNames::IsMobileRole:
return m_tabs.at(index.row()).isMobile();
}
return {};
......@@ -73,18 +76,28 @@ int TabsModel::rowCount(const QModelIndex &parent) const
* is not wanted, e.g if this function is already triggered by a load of the web engine.
* @param index
* @param url
* @param isMobile
*/
void TabsModel::setTabUrl(int index, QString url)
void TabsModel::setTab(int index, QString url, bool isMobile)
{
if (index < 0 && index >= m_tabs.count())
return; // index out of bounds
m_tabs.replace(index, url);
m_tabs[index].setUrl(url);
m_tabs[index].setIsMobile(isMobile);
saveTabs();
tabsChanged();
}
TabState TabsModel::tab(int index) {
if (index < 0 && index >= m_tabs.count())
return {}; // index out of bounds
return m_tabs.at(index);
}
int TabsModel::currentTab() const
{
return m_currentTab;
......@@ -100,29 +113,87 @@ void TabsModel::setCurrentTab(int index)
saveTabs();
}
QList<QString> TabsModel::tabs() const
QVector<TabState> TabsModel::tabs() const
{
return m_tabs;
}
void TabsModel::loadTabs()
bool TabsModel::loadTabs()
{
beginResetModel();
m_tabs = m_settings->value(QStringLiteral("browser/tabs"), QStringList()).toStringList();
endResetModel();
tabsChanged();
if (!m_privateMode) {
beginResetModel();
QString input = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)
+ QStringLiteral("/angelfish/tabs.json");
m_currentTab = m_settings->value(QStringLiteral("browser/currentTab"), 0).toInt();
currentTabChanged();
QFile inputFile(input);
if (!inputFile.exists()) {
return false;
}
if (!inputFile.open(QIODevice::ReadOnly)) {
qDebug() << "Failed to load tabs from disk";
}
const auto tabsStorage = QJsonDocument::fromJson(inputFile.readAll()).object();
m_tabs.clear();
for (const auto tab : tabsStorage.value(QLatin1String("tabs")).toArray()) {
m_tabs.append(TabState::fromJson(tab.toObject()));
}
qDebug() << "loaded from file:" << m_tabs.count() << input;
m_currentTab = tabsStorage.value(QLatin1String("currentTab")).toInt();
// Make sure model always contains at least one tab
if (m_tabs.count() == 0) {
createEmptyTab();
}
endResetModel();
tabsChanged();
currentTabChanged();
inputFile.close();
return true;
}
return false;
}
void TabsModel::saveTabs()
bool TabsModel::saveTabs() const
{
// only save if not in private mode
if (!m_privateMode) {
m_settings->setValue(QStringLiteral("browser/tabs"), QVariant(m_tabs));
m_settings->setValue(QStringLiteral("browser/currentTab"), m_currentTab);
QString outputDir = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)
+ QStringLiteral("/angelfish/");
QFile outputFile(outputDir + QLatin1String("tabs.json"));
if (!QDir(outputDir).mkpath(".")) {
qDebug() << "Destdir doesn't exist and I can't create it: " << outputDir;
return false;
}
if (!outputFile.open(QIODevice::WriteOnly)) {
qDebug() << "Failed to write tabs to disk";
}
auto document = QJsonDocument();
auto tabsStorage = QJsonObject();
QJsonArray tabsArray;
for (const auto &tab : m_tabs) {
tabsArray.append(tab.toJson());
}
qDebug() << "Wrote to file" << outputFile.fileName() << "(" << tabsArray.count() << "urls" << ")";
tabsStorage.insert(QLatin1String("tabs"), tabsArray);
tabsStorage.insert(QLatin1String("currentTab"), m_currentTab);
document.setObject(tabsStorage);
outputFile.write(document.toJson());
outputFile.close();
return true;
}
return false;
}
bool TabsModel::privateMode() const
......@@ -141,9 +212,13 @@ void TabsModel::createEmptyTab()
newTab(QStringLiteral("about:blank"));
};
void TabsModel::newTab(QString url) {
void TabsModel::newTab(QString url, bool isMobile) {
beginInsertRows({}, m_tabs.count(), m_tabs.count());
m_tabs.append(url);
QJsonObject tab;
tab.insert(QStringLiteral("url"), url);
m_tabs.append(TabState(url, isMobile));
endInsertRows();
// Switch to last tab
......@@ -195,10 +270,58 @@ void TabsModel::closeTab(int index) {
void TabsModel::load(QString url) {
qDebug() << "Loading url:" << url;
m_tabs.replace(m_currentTab, url);
qDebug() << "current tab" << m_currentTab << "tabs open" << m_tabs.count();
m_tabs[m_currentTab].setUrl(url);
QModelIndex index = createIndex(m_currentTab, m_currentTab);
dataChanged(index, index);
tabsChanged();
}
QString TabState::url() const
{
return m_url;
}
void TabState::setUrl(const QString &url)
{
m_url = url;
}
bool TabState::isMobile() const
{
return m_isMobile;
}
void TabState::setIsMobile(bool isMobile)
{
m_isMobile = isMobile;
}
TabState TabState::fromJson(const QJsonObject &obj)
{
TabState tab;
tab.setUrl(obj.value(QStringLiteral("url")).toString());
tab.setIsMobile(obj.value(QStringLiteral("isMobile")).toBool());
return tab;
}
TabState::TabState(const QString &url, const bool isMobile)
{
setIsMobile(isMobile);
setUrl(url);
}
bool TabState::operator==(const TabState &other) const
{
return (m_url == other.url() && m_isMobile == other.isMobile());
}
QJsonObject TabState::toJson() const
{
QJsonObject obj;
obj.insert(QStringLiteral("url"), m_url);
obj.insert(QStringLiteral("isMobile"), m_isMobile);
return obj;
}
......@@ -20,18 +20,39 @@
#define TABSMODEL_H
#include <QAbstractListModel>
#include <QSettings>
#include <QJsonObject>
class TabState {
public:
static TabState fromJson(const QJsonObject &obj);
QJsonObject toJson() const;
TabState() = default;
TabState(const QString &url, const bool isMobile);
bool operator==(const TabState &other) const;
bool isMobile() const;
void setIsMobile(bool isMobile);
QString url() const;
void setUrl(const QString &url);
private:
QString m_url;
bool m_isMobile;
};
class TabsModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int currentTab READ currentTab WRITE setCurrentTab NOTIFY currentTabChanged)
Q_PROPERTY(QList<QString> tabs READ tabs NOTIFY tabsChanged)
Q_PROPERTY(bool privateMode READ privateMode WRITE setPrivateMode NOTIFY privateModeChanged)
enum RoleNames {
UrlRole = Qt::UserRole + 1
UrlRole = Qt::UserRole + 1,
IsMobileRole
};
public:
......@@ -42,14 +63,14 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int currentTab() const;
QList<QString> tabs() const;
void setCurrentTab(int index);
Q_INVOKABLE void setTabUrl(int index, QString url);
QVector<TabState> tabs() const;
Q_INVOKABLE void setTab(int index, QString url, bool isMobile = false);
Q_INVOKABLE TabState tab(int index);
Q_INVOKABLE void newTab(QString url);
Q_INVOKABLE void newTab(QString url, bool isMobile = false);
Q_INVOKABLE void createEmptyTab();
Q_INVOKABLE void closeTab(int index);
Q_INVOKABLE void load(QString url);
......@@ -58,14 +79,12 @@ public:
void setPrivateMode(bool privateMode);
protected:
void loadTabs();
void saveTabs();
bool loadTabs();
bool saveTabs() const;
private:
QSettings *m_settings;
int m_currentTab = 0;
QList<QString> m_tabs;
QVector<TabState> m_tabs {};
bool m_privateMode = false;
signals:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment