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
)
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)
falkon_tests(
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/tabbar.cpp
tabwidget/tabicon.cpp
tabwidget/tabmodel.cpp
tabwidget/tabstackedwidget.cpp
tabwidget/tabwidget.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
* 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
*
@ -70,7 +71,7 @@ void TabStackedWidget::setTabBar(ComboTabBar* tb)
setFocusProxy(m_tabBar);
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()));
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
{
return m_tabBar->currentIndex();

View File

@ -1,6 +1,7 @@
/* ============================================================
* Falkon - Qt web browser
* 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
* 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());
void removeTab(int index);
void moveTab(int from, int to);
int currentIndex() const;
QWidget* currentWidget() const;

View File

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

View File

@ -128,6 +128,9 @@ public slots:
signals:
void changed();
void tabInserted(int index);
void tabRemoved(int index);
void tabMoved(int from, int to);
private slots:
void loadSettings();
@ -136,7 +139,7 @@ private slots:
void aboutToShowClosedTabsMenu();
void actionChangeIndex();
void tabMoved(int before, int after);
void tabWasMoved(int before, int after);
private:
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(loadStarted()), this, SLOT(loadStarted()));
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
connect(m_tabIcon, &TabIcon::resized, this, [this]() {
@ -324,6 +326,7 @@ void WebTab::reload()
void WebTab::unload()
{
m_savedTab = SavedTab(this);
emit restoredChanged(isRestored());
m_webView->setPage(new WebPage);
m_webView->setFocus();
}
@ -340,7 +343,12 @@ bool WebTab::isPinned() const
void WebTab::setPinned(bool state)
{
if (m_isPinned == state) {
return;
}
m_isPinned = state;
emit pinnedChanged(m_isPinned);
}
bool WebTab::isMuted() const
@ -378,10 +386,11 @@ void WebTab::restoreTab(const WebTab::SavedTab &tab)
{
Q_ASSERT(m_tabBar);
m_isPinned = tab.isPinned;
setPinned(tab.isPinned);
if (!m_isPinned && qzSettings->loadTabsOnActivation) {
if (!isPinned() && qzSettings->loadTabsOnActivation) {
m_savedTab = tab;
emit restoredChanged(isRestored());
int index = tabIndex();
m_tabBar->setTabText(index, tab.title);
@ -440,10 +449,10 @@ void WebTab::loadStarted()
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()) {
return;
@ -468,6 +477,7 @@ void WebTab::tabActivated()
}
p_restoreTab(m_savedTab);
m_savedTab.clear();
emit restoredChanged(isRestored());
});
}
@ -495,7 +505,6 @@ void WebTab::togglePinned()
Q_ASSERT(m_tabBar);
Q_ASSERT(m_window);
m_isPinned = !m_isPinned;
setPinned(!isPinned());
m_window->tabWidget()->pinUnPinTab(tabIndex(), title());
}

View File

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