1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 10:46:35 +01:00

Add TabModel

This commit is contained in:
David Rosca 2018-01-30 14:53:18 +01:00
parent f8531ac632
commit 2377503517
No known key found for this signature in database
GPG Key ID: EBC3FC294452C6D8
12 changed files with 377 additions and 11 deletions

View File

@ -23,6 +23,12 @@ falkon_tests(
webviewtest webviewtest
) )
set(falkon_autotests_SRCS ${CMAKE_SOURCE_DIR}/tests/modeltest/modeltest.cpp)
include_directories(${CMAKE_SOURCE_DIR}/tests/modeltest)
falkon_tests(
tabmodeltest
)
set(falkon_autotests_SRCS passwordbackendtest.cpp) set(falkon_autotests_SRCS passwordbackendtest.cpp)
falkon_tests( falkon_tests(
databasepasswordbackendtest databasepasswordbackendtest

118
autotests/tabmodeltest.cpp Normal file
View File

@ -0,0 +1,118 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "tabmodeltest.h"
#include "autotests.h"
#include "tabmodel.h"
#include "webtab.h"
#include "tabwidget.h"
#include "tabbedwebview.h"
#include "mainapplication.h"
#include "browserwindow.h"
#include "modeltest.h"
void TabModelTest::initTestCase()
{
}
void TabModelTest::cleanupTestCase()
{
}
void TabModelTest::basicTest()
{
BrowserWindow *w = mApp->createWindow(Qz::BW_NewWindow);
TabModel model1(w);
ModelTest modelTest(&model1);
QSignalSpy rowsInsertedSpy(&model1, &TabModel::rowsInserted);
QSignalSpy rowsRemovedSpy(&model1, &TabModel::rowsRemoved);
QCOMPARE(model1.rowCount(), 0);
rowsInsertedSpy.wait();
QCOMPARE(rowsInsertedSpy.count(), 1);
WebTab *tab0 = w->weView(0)->webTab();
QCOMPARE(rowsInsertedSpy.at(0).at(0).value<QModelIndex>(), QModelIndex());
QCOMPARE(rowsInsertedSpy.at(0).at(1).toInt(), 0);
QCOMPARE(rowsInsertedSpy.at(0).at(2).toInt(), 0);
QCOMPARE(model1.data(model1.index(0, 0), TabModel::WebTabRole).value<WebTab*>(), tab0);
rowsInsertedSpy.clear();
w->tabWidget()->addView(QUrl("http://test.com"));
QCOMPARE(rowsInsertedSpy.count(), 1);
WebTab *tab1 = w->weView(1)->webTab();
QCOMPARE(rowsInsertedSpy.at(0).at(0).value<QModelIndex>(), QModelIndex());
QCOMPARE(rowsInsertedSpy.at(0).at(1).toInt(), 1);
QCOMPARE(rowsInsertedSpy.at(0).at(2).toInt(), 1);
QCOMPARE(model1.data(model1.index(1, 0), TabModel::WebTabRole).value<WebTab*>(), tab1);
w->tabWidget()->moveTab(0, 1);
QCOMPARE(w->weView(0)->webTab(), tab1);
QCOMPARE(w->weView(1)->webTab(), tab0);
w->tabWidget()->moveTab(1, 0);
QCOMPARE(w->weView(0)->webTab(), tab0);
QCOMPARE(w->weView(1)->webTab(), tab1);
w->tabWidget()->moveTab(0, 1);
QCOMPARE(w->weView(0)->webTab(), tab1);
QCOMPARE(w->weView(1)->webTab(), tab0);
QCOMPARE(rowsRemovedSpy.count(), 0);
w->tabWidget()->closeTab(1);
QCOMPARE(rowsRemovedSpy.count(), 1);
QCOMPARE(rowsRemovedSpy.at(0).at(0).value<QModelIndex>(), QModelIndex());
QCOMPARE(rowsRemovedSpy.at(0).at(1).toInt(), 1);
QCOMPARE(rowsRemovedSpy.at(0).at(2).toInt(), 1);
QCOMPARE(model1.rowCount(), 1);
TabModel model2(w);
ModelTest modelTest2(&model2);
QCOMPARE(model2.rowCount(), 1);
delete w;
}
void TabModelTest::dataTest()
{
BrowserWindow *w = mApp->createWindow(Qz::BW_NewWindow);
TabModel model(w);
ModelTest modelTest(&model);
QTRY_COMPARE(model.rowCount(), 1);
WebTab *tab0 = w->weView(0)->webTab();
QCOMPARE(model.index(0, 0).data(TabModel::TitleRole).toString(), tab0->title());
QCOMPARE(model.index(0, 0).data(Qt::DisplayRole).toString(), tab0->title());
QCOMPARE(model.index(0, 0).data(TabModel::IconRole).value<QIcon>().pixmap(16), tab0->icon().pixmap(16));
QCOMPARE(model.index(0, 0).data(Qt::DecorationRole).value<QIcon>().pixmap(16), tab0->icon().pixmap(16));
QCOMPARE(model.index(0, 0).data(TabModel::PinnedRole).toBool(), tab0->isPinned());
QCOMPARE(model.index(0, 0).data(TabModel::RestoredRole).toBool(), tab0->isRestored());
delete w;
}
FALKONTEST_MAIN(TabModelTest)

32
autotests/tabmodeltest.h Normal file
View File

@ -0,0 +1,32 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#pragma once
#include <QObject>
class TabModelTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void basicTest();
void dataTest();
};

View File

@ -179,6 +179,7 @@ set(SRCS ${SRCS}
tabwidget/combotabbar.cpp tabwidget/combotabbar.cpp
tabwidget/tabbar.cpp tabwidget/tabbar.cpp
tabwidget/tabicon.cpp tabwidget/tabicon.cpp
tabwidget/tabmodel.cpp
tabwidget/tabstackedwidget.cpp tabwidget/tabstackedwidget.cpp
tabwidget/tabwidget.cpp tabwidget/tabwidget.cpp
tabwidget/tabcontextmenu.cpp tabwidget/tabcontextmenu.cpp

View File

@ -0,0 +1,122 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "tabmodel.h"
#include "webtab.h"
#include "tabwidget.h"
#include "tabbedwebview.h"
#include "browserwindow.h"
TabModel::TabModel(BrowserWindow *window, QObject *parent)
: QAbstractListModel(parent)
, m_window(window)
{
init();
}
WebTab *TabModel::webTab(int row) const
{
return m_tabs.value(row);
}
int TabModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_window->tabCount();
}
QVariant TabModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() > m_window->tabCount()) {
return QVariant();
}
WebTab *tab = webTab(index.row());
if (!tab) {
return QVariant();
}
switch (role) {
case WebTabRole:
return QVariant::fromValue(tab);
case TitleRole:
case Qt::DisplayRole:
return tab->title();
case IconRole:
case Qt::DecorationRole:
return tab->icon();
case PinnedRole:
return tab->isPinned();
case RestoredRole:
return tab->isRestored();
default:
return QVariant();
}
}
void TabModel::init()
{
for (int i = 0; i < m_window->tabCount(); ++i) {
tabInserted(i);
}
connect(m_window->tabWidget(), &TabWidget::tabInserted, this, &TabModel::tabInserted);
connect(m_window->tabWidget(), &TabWidget::tabRemoved, this, &TabModel::tabRemoved);
connect(m_window->tabWidget(), &TabWidget::tabMoved, this, &TabModel::tabMoved);
}
void TabModel::tabInserted(int index)
{
WebTab *tab = m_window->weView(index)->webTab();
beginInsertRows(QModelIndex(), index, index);
m_tabs.insert(index, tab);
endInsertRows();
auto emitDataChanged = [this](WebTab *tab, int role) {
const QModelIndex idx = TabModel::index(tab->tabIndex(), 0);
emit dataChanged(idx, idx, {role});
};
connect(tab, &WebTab::titleChanged, this, std::bind(emitDataChanged, tab, Qt::DisplayRole));
connect(tab, &WebTab::titleChanged, this, std::bind(emitDataChanged, tab, TitleRole));
connect(tab, &WebTab::iconChanged, this, std::bind(emitDataChanged, tab, Qt::DecorationRole));
connect(tab, &WebTab::iconChanged, this, std::bind(emitDataChanged, tab, IconRole));
connect(tab, &WebTab::pinnedChanged, this, std::bind(emitDataChanged, tab, PinnedRole));
connect(tab, &WebTab::restoredChanged, this, std::bind(emitDataChanged, tab, RestoredRole));
}
void TabModel::tabRemoved(int index)
{
beginRemoveRows(QModelIndex(), index, index);
m_tabs.remove(index);
endRemoveRows();
}
void TabModel::tabMoved(int from, int to)
{
beginMoveRows(QModelIndex(), from, from, QModelIndex(), to > from ? to + 1 : to);
m_tabs.insert(to, m_tabs.takeAt(from));
endMoveRows();
}

View File

@ -0,0 +1,55 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#pragma once
#include <QAbstractListModel>
#include "qzcommon.h"
class WebTab;
class BrowserWindow;
class FALKON_EXPORT TabModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
WebTabRole = Qt::UserRole + 1,
TitleRole = Qt::UserRole + 2,
IconRole = Qt::UserRole + 3,
PinnedRole = Qt::UserRole + 4,
RestoredRole = Qt::UserRole + 5,
};
explicit TabModel(BrowserWindow *window, QObject *parent = nullptr);
WebTab *webTab(int row) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
void init();
void tabInserted(int index);
void tabRemoved(int index);
void tabMoved(int from, int to);
BrowserWindow *m_window;
QVector<WebTab*> m_tabs;
};

View File

@ -1,6 +1,7 @@
/* ============================================================ /* ============================================================
* Falkon - Qt web browser * Falkon - Qt web browser
* Copyright (C) 2013-2014 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com> * Copyright (C) 2013-2014 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com>
* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
* *
* Some code was taken from qtabwidget.cpp * Some code was taken from qtabwidget.cpp
* *
@ -70,7 +71,7 @@ void TabStackedWidget::setTabBar(ComboTabBar* tb)
setFocusProxy(m_tabBar); setFocusProxy(m_tabBar);
connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(showTab(int))); connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(showTab(int)));
connect(m_tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(tabWasMoved(int,int))); connect(m_tabBar, &ComboTabBar::tabMoved, this, &TabStackedWidget::tabWasMoved);
connect(m_tabBar, SIGNAL(overFlowChanged(bool)), this, SLOT(setUpLayout())); connect(m_tabBar, SIGNAL(overFlowChanged(bool)), this, SLOT(setUpLayout()));
if (m_tabBar->tabsClosable()) { if (m_tabBar->tabsClosable()) {
@ -289,6 +290,11 @@ void TabStackedWidget::removeTab(int index)
} }
} }
void TabStackedWidget::moveTab(int from, int to)
{
m_tabBar->moveTab(from, to);
}
int TabStackedWidget::currentIndex() const int TabStackedWidget::currentIndex() const
{ {
return m_tabBar->currentIndex(); return m_tabBar->currentIndex();

View File

@ -1,6 +1,7 @@
/* ============================================================ /* ============================================================
* Falkon - Qt web browser * Falkon - Qt web browser
* Copyright (C) 2013-2014 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com> * Copyright (C) 2013-2014 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com>
* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -53,6 +54,7 @@ public:
int pinUnPinTab(int index, const QString &title = QString()); int pinUnPinTab(int index, const QString &title = QString());
void removeTab(int index); void removeTab(int index);
void moveTab(int from, int to);
int currentIndex() const; int currentIndex() const;
QWidget* currentWidget() const; QWidget* currentWidget() const;

View File

@ -99,7 +99,7 @@ TabWidget::TabWidget(BrowserWindow* window, QWidget* parent)
connect(this, &TabStackedWidget::pinStateChanged, this, &TabWidget::changed); connect(this, &TabStackedWidget::pinStateChanged, this, &TabWidget::changed);
connect(m_tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(requestCloseTab(int))); connect(m_tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(requestCloseTab(int)));
connect(m_tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int,int))); connect(m_tabBar, &TabBar::tabMoved, this, &TabWidget::tabWasMoved);
connect(m_tabBar, SIGNAL(moveAddTabButton(int)), this, SLOT(moveAddTabButton(int))); connect(m_tabBar, SIGNAL(moveAddTabButton(int)), this, SLOT(moveAddTabButton(int)));
@ -369,6 +369,8 @@ int TabWidget::addView(const LoadRequest &req, const QString &title, const Qz::N
} }
emit changed(); emit changed();
emit tabInserted(index);
return index; return index;
} }
@ -399,6 +401,8 @@ int TabWidget::insertView(int index, WebTab *tab, const Qz::NewTabPositionFlags
} }
emit changed(); emit changed();
emit tabInserted(newIndex);
return newIndex; return newIndex;
} }
@ -443,6 +447,7 @@ void TabWidget::closeTab(int index)
updateClosedTabsButton(); updateClosedTabsButton();
emit changed(); emit changed();
emit tabRemoved(index);
} }
void TabWidget::requestCloseTab(int index) void TabWidget::requestCloseTab(int index)
@ -499,7 +504,7 @@ void TabWidget::currentTabChanged(int index)
emit changed(); emit changed();
} }
void TabWidget::tabMoved(int before, int after) void TabWidget::tabWasMoved(int before, int after)
{ {
Q_UNUSED(before) Q_UNUSED(before)
Q_UNUSED(after) Q_UNUSED(after)
@ -508,6 +513,7 @@ void TabWidget::tabMoved(int before, int after)
m_lastTabIndex = before; m_lastTabIndex = before;
emit changed(); emit changed();
emit tabMoved(before, after);
} }
void TabWidget::setCurrentIndex(int index) void TabWidget::setCurrentIndex(int index)

View File

@ -128,6 +128,9 @@ public slots:
signals: signals:
void changed(); void changed();
void tabInserted(int index);
void tabRemoved(int index);
void tabMoved(int from, int to);
private slots: private slots:
void loadSettings(); void loadSettings();
@ -136,7 +139,7 @@ private slots:
void aboutToShowClosedTabsMenu(); void aboutToShowClosedTabsMenu();
void actionChangeIndex(); void actionChangeIndex();
void tabMoved(int before, int after); void tabWasMoved(int before, int after);
private: private:
WebTab* weTab(); WebTab* weTab();

View File

@ -158,7 +158,9 @@ WebTab::WebTab(BrowserWindow* window)
connect(m_webView, SIGNAL(showNotification(QWidget*)), this, SLOT(showNotification(QWidget*))); connect(m_webView, SIGNAL(showNotification(QWidget*)), this, SLOT(showNotification(QWidget*)));
connect(m_webView, SIGNAL(loadStarted()), this, SLOT(loadStarted())); connect(m_webView, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
connect(m_webView, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished())); connect(m_webView, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished()));
connect(m_webView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString))); connect(m_webView, &TabbedWebView::titleChanged, this, &WebTab::titleWasChanged);
connect(m_webView, &TabbedWebView::titleChanged, this, &WebTab::titleChanged);
connect(m_webView, &TabbedWebView::iconChanged, this, &WebTab::iconChanged);
// Workaround QTabBar not immediately noticing resizing of tab buttons // Workaround QTabBar not immediately noticing resizing of tab buttons
connect(m_tabIcon, &TabIcon::resized, this, [this]() { connect(m_tabIcon, &TabIcon::resized, this, [this]() {
@ -324,6 +326,7 @@ void WebTab::reload()
void WebTab::unload() void WebTab::unload()
{ {
m_savedTab = SavedTab(this); m_savedTab = SavedTab(this);
emit restoredChanged(isRestored());
m_webView->setPage(new WebPage); m_webView->setPage(new WebPage);
m_webView->setFocus(); m_webView->setFocus();
} }
@ -340,7 +343,12 @@ bool WebTab::isPinned() const
void WebTab::setPinned(bool state) void WebTab::setPinned(bool state)
{ {
if (m_isPinned == state) {
return;
}
m_isPinned = state; m_isPinned = state;
emit pinnedChanged(m_isPinned);
} }
bool WebTab::isMuted() const bool WebTab::isMuted() const
@ -378,10 +386,11 @@ void WebTab::restoreTab(const WebTab::SavedTab &tab)
{ {
Q_ASSERT(m_tabBar); Q_ASSERT(m_tabBar);
m_isPinned = tab.isPinned; setPinned(tab.isPinned);
if (!m_isPinned && qzSettings->loadTabsOnActivation) { if (!isPinned() && qzSettings->loadTabsOnActivation) {
m_savedTab = tab; m_savedTab = tab;
emit restoredChanged(isRestored());
int index = tabIndex(); int index = tabIndex();
m_tabBar->setTabText(index, tab.title); m_tabBar->setTabText(index, tab.title);
@ -440,10 +449,10 @@ void WebTab::loadStarted()
void WebTab::loadFinished() void WebTab::loadFinished()
{ {
titleChanged(m_webView->title()); titleWasChanged(m_webView->title());
} }
void WebTab::titleChanged(const QString &title) void WebTab::titleWasChanged(const QString &title)
{ {
if (!m_tabBar || !m_window || title.isEmpty()) { if (!m_tabBar || !m_window || title.isEmpty()) {
return; return;
@ -468,6 +477,7 @@ void WebTab::tabActivated()
} }
p_restoreTab(m_savedTab); p_restoreTab(m_savedTab);
m_savedTab.clear(); m_savedTab.clear();
emit restoredChanged(isRestored());
}); });
} }
@ -495,7 +505,6 @@ void WebTab::togglePinned()
Q_ASSERT(m_tabBar); Q_ASSERT(m_tabBar);
Q_ASSERT(m_window); Q_ASSERT(m_window);
m_isPinned = !m_isPinned; setPinned(!isPinned());
m_window->tabWidget()->pinUnPinTab(tabIndex(), title()); m_window->tabWidget()->pinUnPinTab(tabIndex(), title());
} }

View File

@ -109,9 +109,15 @@ private slots:
void showNotification(QWidget* notif); void showNotification(QWidget* notif);
void loadStarted(); void loadStarted();
void loadFinished(); void loadFinished();
signals:
void titleChanged(const QString &title); void titleChanged(const QString &title);
void iconChanged(const QIcon &icon);
void pinnedChanged(bool pinned);
void restoredChanged(bool restored);
private: private:
void titleWasChanged(const QString &title);
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
BrowserWindow* m_window; BrowserWindow* m_window;