mirror of
https://invent.kde.org/network/falkon.git
synced 2024-12-24 04:36:34 +01:00
Bookmarks: Added BookmarksTree class that manages all bookmark's view types.
-BookmarksSidebar, BookmarksWidget,BookmarksManager and ... use BookmarksTree -Added 'New Folder...' -Fixed some issues
This commit is contained in:
parent
a0203c3fbb
commit
8f2b9a00e0
@ -46,6 +46,7 @@ BookmarksManager::BookmarksManager(QupZilla* mainClass, QWidget* parent)
|
||||
, m_bookmarksModel(mApp->bookmarksModel())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->bookmarksTree->setViewType(BookmarksTree::ManagerView);
|
||||
|
||||
ui->bookmarksTree->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
ui->bookmarksTree->setDragDropReceiver(true, m_bookmarksModel);
|
||||
@ -103,14 +104,57 @@ void BookmarksManager::setMainWindow(QupZilla* window)
|
||||
}
|
||||
}
|
||||
|
||||
void BookmarksManager::addFolder()
|
||||
void BookmarksManager::addFolder(QWidget* parent, QString* folder, bool showInsertDialog,
|
||||
const QString &bookmarkTitle, WebView* view)
|
||||
{
|
||||
QString text = QInputDialog::getText(this, tr("Add new folder"), tr("Choose name for new bookmark folder: "));
|
||||
BookmarksTree* bookmarksTree = qobject_cast<BookmarksTree*>(sender());
|
||||
QDialog dialog(parent ? parent : this);
|
||||
dialog.setWindowTitle(tr("Add new folder"));
|
||||
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom, &dialog);
|
||||
QLabel* labelParent = new QLabel(tr("Choose parent folder for new folder: "), &dialog);
|
||||
QComboBox* combo = new QComboBox(&dialog);
|
||||
combo->addItem(qIconProvider->fromTheme("user-bookmarks"), tr("Bookmarks"), "NO_PARENT");
|
||||
combo->addItem(style()->standardIcon(QStyle::SP_DirOpenIcon), _bookmarksToolbar, "bookmarksToolbar");
|
||||
combo->setCurrentIndex(0);
|
||||
QLabel* labelFolder = new QLabel(tr("Choose name for new bookmark folder: "), &dialog);
|
||||
QLineEdit* edit = new QLineEdit(&dialog);
|
||||
QDialogButtonBox* box = new QDialogButtonBox(&dialog);
|
||||
box->addButton(QDialogButtonBox::Ok);
|
||||
box->addButton(QDialogButtonBox::Cancel);
|
||||
connect(box, SIGNAL(rejected()), &dialog, SLOT(reject()));
|
||||
connect(box, SIGNAL(accepted()), &dialog, SLOT(accept()));
|
||||
layout->addWidget(labelParent);
|
||||
layout->addWidget(combo);
|
||||
layout->addWidget(labelFolder);
|
||||
layout->addWidget(edit);
|
||||
layout->addWidget(box);
|
||||
dialog.exec();
|
||||
if (dialog.result() == QDialog::Rejected) {
|
||||
return;
|
||||
}
|
||||
QString text = edit->text();
|
||||
if (text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_bookmarksModel->createFolder(text);
|
||||
bool created = false;
|
||||
if (combo->itemData(combo->currentIndex()).toString() == "bookmarksToolbar") {
|
||||
created = m_bookmarksModel->createSubfolder(text);
|
||||
}
|
||||
else {
|
||||
created = m_bookmarksModel->createFolder(text);
|
||||
}
|
||||
if (folder) {
|
||||
*folder = (created ? text : "");
|
||||
}
|
||||
|
||||
if (created && bookmarksTree && bookmarksTree->viewType() == BookmarksTree::ComboFolderView) {
|
||||
bookmarksTree->refreshTree();
|
||||
}
|
||||
|
||||
if (showInsertDialog) {
|
||||
insertBookmark(view->url(), bookmarkTitle, view->icon(), created ? text : "");
|
||||
}
|
||||
}
|
||||
|
||||
void BookmarksManager::addSubfolder()
|
||||
@ -315,99 +359,7 @@ void BookmarksManager::contextMenuRequested(const QPoint &position)
|
||||
void BookmarksManager::refreshTable()
|
||||
{
|
||||
m_isRefreshing = true;
|
||||
ui->bookmarksTree->setUpdatesEnabled(false);
|
||||
ui->bookmarksTree->clear();
|
||||
|
||||
QSqlQuery query;
|
||||
QTreeWidgetItem* newItem = new QTreeWidgetItem(ui->bookmarksTree);
|
||||
newItem->setText(0, _bookmarksMenu);
|
||||
newItem->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
newItem->setFlags((newItem->flags() & ~Qt::ItemIsDragEnabled) | Qt::ItemIsDropEnabled);
|
||||
ui->bookmarksTree->addTopLevelItem(newItem);
|
||||
|
||||
QTreeWidgetItem* bookmarksToolbar = new QTreeWidgetItem(ui->bookmarksTree);
|
||||
bookmarksToolbar->setText(0, _bookmarksToolbar);
|
||||
bookmarksToolbar->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
bookmarksToolbar->setFlags((bookmarksToolbar->flags() & ~Qt::ItemIsDragEnabled) | Qt::ItemIsDropEnabled);
|
||||
ui->bookmarksTree->addTopLevelItem(bookmarksToolbar);
|
||||
|
||||
query.exec("SELECT name FROM folders WHERE subfolder!='yes'");
|
||||
while (query.next()) {
|
||||
newItem = new QTreeWidgetItem(ui->bookmarksTree);
|
||||
newItem->setText(0, query.value(0).toString());
|
||||
newItem->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
newItem->setFlags(newItem->flags() | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled);
|
||||
ui->bookmarksTree->addTopLevelItem(newItem);
|
||||
}
|
||||
|
||||
query.exec("SELECT title, url, id, folder, icon FROM bookmarks");
|
||||
while (query.next()) {
|
||||
QString title = query.value(0).toString();
|
||||
QUrl url = query.value(1).toUrl();
|
||||
int id = query.value(2).toInt();
|
||||
QString folder = query.value(3).toString();
|
||||
QIcon icon = qIconProvider->iconFromImage(QImage::fromData(query.value(4).toByteArray()));
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem();
|
||||
if (folder == QLatin1String("bookmarksMenu")) {
|
||||
folder = _bookmarksMenu;
|
||||
}
|
||||
if (folder == QLatin1String("bookmarksToolbar")) {
|
||||
folder = _bookmarksToolbar;
|
||||
}
|
||||
|
||||
if (folder != QLatin1String("unsorted")) {
|
||||
QList<QTreeWidgetItem*> findParent = ui->bookmarksTree->findItems(folder, 0);
|
||||
if (findParent.count() != 1) {
|
||||
continue;
|
||||
}
|
||||
findParent.at(0)->addChild(item);
|
||||
}
|
||||
|
||||
item->setText(0, title);
|
||||
item->setText(1, url.toEncoded());
|
||||
item->setToolTip(0, title);
|
||||
item->setToolTip(1, url.toEncoded());
|
||||
|
||||
item->setData(0, Qt::UserRole + 10, id);
|
||||
item->setData(0, Qt::UserRole + 11, url);
|
||||
item->setIcon(0, icon);
|
||||
item->setFlags(item->flags() | Qt::ItemIsEditable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled);
|
||||
ui->bookmarksTree->addTopLevelItem(item);
|
||||
}
|
||||
|
||||
query.exec("SELECT name FROM folders WHERE subfolder='yes'");
|
||||
while (query.next()) {
|
||||
newItem = new QTreeWidgetItem(bookmarksToolbar);
|
||||
newItem->setText(0, query.value(0).toString());
|
||||
newItem->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
newItem->setFlags(newItem->flags() | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
|
||||
QSqlQuery query2;
|
||||
query2.prepare("SELECT title, url, id, icon FROM bookmarks WHERE folder=?");
|
||||
query2.addBindValue(query.value(0).toString());
|
||||
query2.exec();
|
||||
while (query2.next()) {
|
||||
QString title = query2.value(0).toString();
|
||||
QUrl url = query2.value(1).toUrl();
|
||||
int id = query2.value(2).toInt();
|
||||
QIcon icon = qIconProvider->iconFromImage(QImage::fromData(query2.value(3).toByteArray()));
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem(newItem);
|
||||
|
||||
item->setText(0, title);
|
||||
item->setText(1, url.toEncoded());
|
||||
item->setToolTip(0, title);
|
||||
item->setToolTip(1, url.toEncoded());
|
||||
|
||||
item->setData(0, Qt::UserRole + 10, id);
|
||||
item->setData(0, Qt::UserRole + 11, url);
|
||||
item->setIcon(0, icon);
|
||||
item->setFlags(item->flags() | Qt::ItemIsEditable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ui->bookmarksTree->expandAll();
|
||||
ui->bookmarksTree->setUpdatesEnabled(true);
|
||||
ui->bookmarksTree->refreshTree();
|
||||
m_isRefreshing = false;
|
||||
}
|
||||
|
||||
@ -667,7 +619,7 @@ void BookmarksManager::renameFolder(const QString &before, const QString &after)
|
||||
folderItem->setText(0, after);
|
||||
}
|
||||
|
||||
void BookmarksManager::insertBookmark(const QUrl &url, const QString &title, const QIcon &icon)
|
||||
void BookmarksManager::insertBookmark(const QUrl &url, const QString &title, const QIcon &icon, const QString &folder)
|
||||
{
|
||||
if (url.isEmpty() || title.isEmpty()) {
|
||||
return;
|
||||
@ -677,6 +629,16 @@ void BookmarksManager::insertBookmark(const QUrl &url, const QString &title, con
|
||||
QLabel* label = new QLabel(dialog);
|
||||
QLineEdit* edit = new QLineEdit(dialog);
|
||||
QComboBox* combo = new QComboBox(dialog);
|
||||
BookmarksTree *bookmarksTree = new BookmarksTree(dialog);
|
||||
connect(bookmarksTree, SIGNAL(requestNewFolder(QWidget*,QString*,bool,QString,WebView*)),
|
||||
this, SLOT(addFolder(QWidget*,QString*,bool,QString,WebView*)));
|
||||
bookmarksTree->setViewType(BookmarksTree::ComboFolderView);
|
||||
bookmarksTree->header()->hide();
|
||||
bookmarksTree->setColumnCount(1);
|
||||
combo->setModel(bookmarksTree->model());
|
||||
combo->setView(bookmarksTree);
|
||||
bookmarksTree->refreshTree();
|
||||
|
||||
QDialogButtonBox* box = new QDialogButtonBox(dialog);
|
||||
box->addButton(QDialogButtonBox::Ok);
|
||||
box->addButton(QDialogButtonBox::Cancel);
|
||||
@ -690,15 +652,25 @@ void BookmarksManager::insertBookmark(const QUrl &url, const QString &title, con
|
||||
}
|
||||
layout->addWidget(box);
|
||||
|
||||
combo->addItem(QIcon(":icons/other/unsortedbookmarks.png"), _bookmarksUnsorted);
|
||||
combo->addItem(style()->standardIcon(QStyle::SP_DirOpenIcon), _bookmarksMenu);
|
||||
combo->addItem(style()->standardIcon(QStyle::SP_DirOpenIcon), _bookmarksToolbar);
|
||||
QSqlQuery query;
|
||||
query.exec("SELECT name FROM folders");
|
||||
while (query.next()) {
|
||||
combo->addItem(style()->standardIcon(QStyle::SP_DirIcon), query.value(0).toString());
|
||||
int index = combo->findText(BookmarksModel::toTranslatedFolder(folder.isEmpty() ? m_bookmarksModel->lastFolder() : folder));
|
||||
// QComboBox::find() returns index related to the item's parent
|
||||
if (index == -1) { // subfolder or a deleted lastFolder
|
||||
QModelIndex rootIndex = combo->rootModelIndex();
|
||||
combo->setRootModelIndex(combo->model()->index(combo->findText(_bookmarksToolbar),0));
|
||||
index = combo->findText(BookmarksModel::toTranslatedFolder(folder.isEmpty() ? m_bookmarksModel->lastFolder() : folder));
|
||||
if (index == -1) { // deleted lastFolder
|
||||
combo->setRootModelIndex(rootIndex);
|
||||
combo->setCurrentIndex(0);
|
||||
}
|
||||
else {
|
||||
combo->setCurrentIndex(index);
|
||||
combo->setRootModelIndex(rootIndex);
|
||||
}
|
||||
}
|
||||
combo->setCurrentIndex(combo->findText(BookmarksModel::toTranslatedFolder(m_bookmarksModel->lastFolder())));
|
||||
else {
|
||||
combo->setCurrentIndex(index);
|
||||
}
|
||||
connect(combo, SIGNAL(currentIndexChanged(int)), bookmarksTree, SLOT(activeItemChange(int)));
|
||||
|
||||
label->setText(tr("Choose name and location of this bookmark."));
|
||||
edit->setText(title);
|
||||
@ -711,9 +683,11 @@ void BookmarksManager::insertBookmark(const QUrl &url, const QString &title, con
|
||||
dialog->resize(size);
|
||||
dialog->exec();
|
||||
if (dialog->result() == QDialog::Rejected) {
|
||||
delete dialog;
|
||||
return;
|
||||
}
|
||||
if (edit->text().isEmpty()) {
|
||||
delete dialog;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -727,6 +701,14 @@ void BookmarksManager::insertAllTabs()
|
||||
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom, dialog);
|
||||
QLabel* label = new QLabel(dialog);
|
||||
QComboBox* combo = new QComboBox(dialog);
|
||||
BookmarksTree *bookmarksTree = new BookmarksTree(dialog);
|
||||
connect(bookmarksTree, SIGNAL(requestNewFolder(QWidget*,QString*,bool,QString,WebView*)),
|
||||
this, SLOT(addFolder(QWidget*,QString*,bool,QString,WebView*)));
|
||||
bookmarksTree->setViewType(BookmarksTree::ComboFolderView);
|
||||
bookmarksTree->header()->hide();
|
||||
bookmarksTree->setColumnCount(1);
|
||||
combo->setModel(bookmarksTree->model());
|
||||
combo->setView(bookmarksTree);
|
||||
QDialogButtonBox* box = new QDialogButtonBox(dialog);
|
||||
box->addButton(QDialogButtonBox::Ok);
|
||||
box->addButton(QDialogButtonBox::Cancel);
|
||||
@ -736,15 +718,28 @@ void BookmarksManager::insertAllTabs()
|
||||
layout->addWidget(combo);
|
||||
layout->addWidget(box);
|
||||
|
||||
combo->addItem(QIcon(":icons/other/unsortedbookmarks.png"), _bookmarksUnsorted);
|
||||
combo->addItem(style()->standardIcon(QStyle::SP_DirOpenIcon), _bookmarksMenu);
|
||||
combo->addItem(style()->standardIcon(QStyle::SP_DirOpenIcon), _bookmarksToolbar);
|
||||
QSqlQuery query;
|
||||
query.exec("SELECT name FROM folders");
|
||||
while (query.next()) {
|
||||
combo->addItem(style()->standardIcon(QStyle::SP_DirIcon), query.value(0).toString());
|
||||
bookmarksTree->refreshTree();
|
||||
|
||||
|
||||
int index = combo->findText(BookmarksModel::toTranslatedFolder(m_bookmarksModel->lastFolder()));
|
||||
// QComboBox::find() returns index related to the item's parent
|
||||
if (index == -1) { // subfolder or a deleted lastFolder
|
||||
QModelIndex rootIndex = combo->rootModelIndex();
|
||||
combo->setRootModelIndex(combo->model()->index(combo->findText(_bookmarksToolbar),0));
|
||||
index = combo->findText(BookmarksModel::toTranslatedFolder(m_bookmarksModel->lastFolder()));
|
||||
if (index == -1) { // deleted lastFolder
|
||||
combo->setRootModelIndex(rootIndex);
|
||||
combo->setCurrentIndex(0);
|
||||
}
|
||||
else {
|
||||
combo->setCurrentIndex(index);
|
||||
combo->setRootModelIndex(rootIndex);
|
||||
}
|
||||
}
|
||||
combo->setCurrentIndex(combo->findText(BookmarksModel::toTranslatedFolder(m_bookmarksModel->lastFolder())));
|
||||
else {
|
||||
combo->setCurrentIndex(index);
|
||||
}
|
||||
connect(combo, SIGNAL(currentIndexChanged(int)), bookmarksTree, SLOT(activeItemChange(int)));
|
||||
|
||||
label->setText(tr("Choose folder for bookmarks:"));
|
||||
dialog->setWindowTitle(tr("Bookmark All Tabs"));
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
explicit BookmarksManager(QupZilla* mainClass, QWidget* parent = 0);
|
||||
~BookmarksManager();
|
||||
void addBookmark(WebView* view);
|
||||
void insertBookmark(const QUrl &url, const QString &title, const QIcon &icon);
|
||||
void insertBookmark(const QUrl &url, const QString &title, const QIcon &icon, const QString &folder = QString());
|
||||
void setMainWindow(QupZilla* window);
|
||||
|
||||
void search(const QString &string);
|
||||
@ -56,7 +56,8 @@ private slots:
|
||||
void deleteItem();
|
||||
void itemChanged(QTreeWidgetItem* item);
|
||||
void addSubfolder();
|
||||
void addFolder();
|
||||
void addFolder(QWidget *parent = 0, QString* folder = 0, bool showInsertDialog = false,
|
||||
const QString &bookmarkTitle = QString(), WebView* = 0);
|
||||
void renameFolder();
|
||||
void contextMenuRequested(const QPoint &position);
|
||||
void loadInNewTab();
|
||||
@ -87,5 +88,4 @@ private:
|
||||
QPointer<QupZilla> p_QupZilla;
|
||||
BookmarksModel* m_bookmarksModel;
|
||||
};
|
||||
|
||||
#endif // BOOKMARKSMANAGER_H
|
||||
|
@ -14,35 +14,6 @@
|
||||
<string>Bookmarks</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="7">
|
||||
<widget class="TreeWidget" name="bookmarksTree">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ContiguousSelection</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>330</number>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Title</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Url</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="4">
|
||||
<widget class="QPushButton" name="addFolder">
|
||||
<property name="text">
|
||||
@ -89,19 +60,48 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="7">
|
||||
<widget class="BookmarksTree" name="bookmarksTree">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ContiguousSelection</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>330</number>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Title</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Url</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>TreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>treewidget.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ClickableLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>clickablelabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BookmarksTree</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>bookmarkstree.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
241
src/lib/bookmarks/bookmarkstree.cpp
Normal file
241
src/lib/bookmarks/bookmarkstree.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
/* ============================================================
|
||||
* QupZilla - WebKit based browser
|
||||
* Copyright (C) 2012 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com>
|
||||
* Copyright (C) 2010-2012 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 "bookmarkstree.h"
|
||||
#include "iconprovider.h"
|
||||
#include "bookmarksmodel.h"
|
||||
|
||||
#include <QSqlQuery>
|
||||
#include <QComboBox>
|
||||
|
||||
BookmarksTree::BookmarksTree(QWidget *parent)
|
||||
: TreeWidget(parent)
|
||||
, m_viewType(ManagerView)
|
||||
{
|
||||
}
|
||||
|
||||
void BookmarksTree::setViewType(BookmarksTree::BookmarkView viewType)
|
||||
{
|
||||
if (viewType != m_viewType) {
|
||||
if (m_viewType == ComboFolderView) {
|
||||
setItemsExpandable(true);
|
||||
setRootIsDecorated(true);
|
||||
setIndentation(20); //QTreeView default indentation
|
||||
}
|
||||
else if (viewType == ComboFolderView) {
|
||||
setItemsExpandable(false);
|
||||
setRootIsDecorated(false);
|
||||
setIndentation(10);
|
||||
}
|
||||
m_viewType = viewType;
|
||||
}
|
||||
}
|
||||
|
||||
void BookmarksTree::drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const
|
||||
{
|
||||
if (m_viewType == ComboFolderView) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeWidget::drawBranches(painter, rect, index);
|
||||
}
|
||||
|
||||
void BookmarksTree::refreshTree()
|
||||
{
|
||||
setUpdatesEnabled(false);
|
||||
clear();
|
||||
|
||||
QSqlQuery query;
|
||||
QTreeWidgetItem* rootItem = invisibleRootItem();
|
||||
if (m_viewType == ExportFolderView) {
|
||||
rootItem = new QTreeWidgetItem(this);
|
||||
rootItem->setText(0, tr("Bookmarks"));
|
||||
rootItem->setIcon(0, qIconProvider->fromTheme("user-bookmarks"));
|
||||
addTopLevelItem(rootItem);
|
||||
}
|
||||
|
||||
if (m_viewType == ComboFolderView) {
|
||||
QTreeWidgetItem* newItem = new QTreeWidgetItem(rootItem);
|
||||
newItem->setText(0, _bookmarksUnsorted);
|
||||
newItem->setData(0, Qt::UserRole, "unsorted");
|
||||
newItem->setIcon(0, QIcon(":/icons/other/unsortedbookmarks.png"));
|
||||
addTopLevelItem(newItem);
|
||||
}
|
||||
|
||||
|
||||
QTreeWidgetItem* newItem = new QTreeWidgetItem(rootItem);
|
||||
newItem->setText(0, _bookmarksMenu);
|
||||
newItem->setData(0, Qt::UserRole, "bookmarksMenu");
|
||||
newItem->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
if (m_viewType != ComboFolderView) {
|
||||
newItem->setFlags((newItem->flags() & ~Qt::ItemIsDragEnabled) | Qt::ItemIsDropEnabled);
|
||||
}
|
||||
addTopLevelItem(newItem);
|
||||
|
||||
QTreeWidgetItem* bookmarksToolbar;
|
||||
if (m_viewType != SideBarView) {
|
||||
bookmarksToolbar = new QTreeWidgetItem(rootItem);
|
||||
bookmarksToolbar->setText(0, _bookmarksToolbar);
|
||||
bookmarksToolbar->setData(0, Qt::UserRole, "bookmarksToolbar");
|
||||
bookmarksToolbar->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
if (m_viewType != ComboFolderView) {
|
||||
bookmarksToolbar->setFlags((bookmarksToolbar->flags() & ~Qt::ItemIsDragEnabled)
|
||||
| Qt::ItemIsDropEnabled);
|
||||
}
|
||||
addTopLevelItem(bookmarksToolbar);
|
||||
}
|
||||
|
||||
query.exec("SELECT name FROM folders WHERE subfolder!='yes'");
|
||||
while (query.next()) {
|
||||
newItem = new QTreeWidgetItem(rootItem);
|
||||
newItem->setText(0, query.value(0).toString());
|
||||
newItem->setData(0, Qt::UserRole, query.value(0).toString());
|
||||
newItem->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
newItem->setFlags(newItem->flags() | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled);
|
||||
addTopLevelItem(newItem);
|
||||
}
|
||||
if (m_viewType == ComboFolderView) {
|
||||
QTreeWidgetItem *newFolder = new QTreeWidgetItem(rootItem);
|
||||
newFolder->setText(0, tr("New Folder..."));
|
||||
newFolder->setData(0, Qt::UserRole + 12, "NEW_FOLDER");
|
||||
newFolder->setIcon(0, style()->standardIcon(QStyle::SP_FileDialogNewFolder));
|
||||
}
|
||||
|
||||
if (m_viewType != ComboFolderView) {
|
||||
query.exec("SELECT title, url, id, folder, icon FROM bookmarks");
|
||||
while (query.next()) {
|
||||
QString title = query.value(0).toString();
|
||||
QUrl url = query.value(1).toUrl();
|
||||
int id = query.value(2).toInt();
|
||||
QString folder = query.value(3).toString();
|
||||
QIcon icon = qIconProvider->iconFromImage(QImage::fromData(query.value(4).toByteArray()));
|
||||
QTreeWidgetItem* item;
|
||||
if (folder == QLatin1String("bookmarksMenu")) {
|
||||
folder = _bookmarksMenu;
|
||||
}
|
||||
if (folder == QLatin1String("bookmarksToolbar")) {
|
||||
folder = _bookmarksToolbar;
|
||||
}
|
||||
|
||||
if (folder != QLatin1String("unsorted")) {
|
||||
QList<QTreeWidgetItem*> findParent = findItems(folder, 0);
|
||||
if (findParent.count() != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item = new QTreeWidgetItem(findParent.at(0));
|
||||
|
||||
}
|
||||
else {
|
||||
item = new QTreeWidgetItem(rootItem);
|
||||
}
|
||||
|
||||
item->setText(0, title);
|
||||
item->setText(1, url.toEncoded());
|
||||
|
||||
if (m_viewType != SideBarView) {
|
||||
item->setToolTip(0, title);
|
||||
item->setToolTip(1, url.toEncoded());
|
||||
// Qt::ItemIsEditable just Manager!!
|
||||
item->setFlags(item->flags() | Qt::ItemIsEditable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled);
|
||||
}
|
||||
else {
|
||||
item->setToolTip(0, url.toEncoded());
|
||||
item->setFlags(item->flags() | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled);
|
||||
}
|
||||
|
||||
item->setData(0, Qt::UserRole + 10, id);
|
||||
item->setData(0, Qt::UserRole + 11, url);
|
||||
item->setIcon(0, icon);
|
||||
addTopLevelItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_viewType != SideBarView) {
|
||||
query.exec("SELECT name FROM folders WHERE subfolder='yes'");
|
||||
while (query.next()) {
|
||||
newItem = new QTreeWidgetItem(bookmarksToolbar);
|
||||
newItem->setText(0, query.value(0).toString());
|
||||
newItem->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
if (m_viewType != ComboFolderView && m_viewType != ExportFolderView) {
|
||||
newItem->setFlags(newItem->flags() | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
QSqlQuery query2;
|
||||
query2.prepare("SELECT title, url, id, icon FROM bookmarks WHERE folder=?");
|
||||
query2.addBindValue(query.value(0).toString());
|
||||
query2.exec();
|
||||
while (query2.next()) {
|
||||
QString title = query2.value(0).toString();
|
||||
QUrl url = query2.value(1).toUrl();
|
||||
int id = query2.value(2).toInt();
|
||||
QIcon icon = qIconProvider->iconFromImage(QImage::fromData(query2.value(3).toByteArray()));
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem(newItem);
|
||||
|
||||
item->setText(0, title);
|
||||
item->setText(1, url.toEncoded());
|
||||
item->setToolTip(0, title);
|
||||
item->setToolTip(1, url.toEncoded());
|
||||
|
||||
item->setData(0, Qt::UserRole + 10, id);
|
||||
item->setData(0, Qt::UserRole + 11, url);
|
||||
item->setIcon(0, icon);
|
||||
item->setFlags(item->flags() | Qt::ItemIsEditable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expandAll();
|
||||
setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
void BookmarksTree::activeItemChange(int index, QComboBox *combo, const QString &title, WebView* view)
|
||||
{
|
||||
if (!combo) {
|
||||
combo = qobject_cast<QComboBox*>(sender());
|
||||
}
|
||||
if (!combo) {
|
||||
return;
|
||||
}
|
||||
QString data = combo->itemData(index, Qt::UserRole + 12).toString();
|
||||
if (data == "NEW_FOLDER") {
|
||||
if (combo->parentWidget()->objectName() == "BookmarksWidget") {
|
||||
emit requestNewFolder(this, 0, true, title, view);
|
||||
}
|
||||
else {
|
||||
QString folder;
|
||||
emit requestNewFolder(this, &folder, false, QString(), 0);
|
||||
if (!folder.isEmpty()) {
|
||||
int ind = combo->findText(folder);
|
||||
// QComboBox::find() returns index related to the item's parent
|
||||
if (ind == -1) {
|
||||
QModelIndex rootIndex = combo->rootModelIndex();
|
||||
combo->setRootModelIndex(combo->model()->index(combo->findText(_bookmarksToolbar),0));
|
||||
combo->setCurrentIndex(combo->findText(folder));
|
||||
combo->setRootModelIndex(rootIndex);
|
||||
}
|
||||
else {
|
||||
combo->setCurrentIndex(ind);
|
||||
}
|
||||
}
|
||||
else {
|
||||
combo->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
58
src/lib/bookmarks/bookmarkstree.h
Normal file
58
src/lib/bookmarks/bookmarkstree.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* ============================================================
|
||||
* QupZilla - WebKit based browser
|
||||
* Copyright (C) 2012 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com>
|
||||
* Copyright (C) 2010-2012 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/>.
|
||||
* ============================================================ */
|
||||
#ifndef BOOKMARKSTREE_H
|
||||
#define BOOKMARKSTREE_H
|
||||
|
||||
#include "treewidget.h"
|
||||
#include "qz_namespace.h"
|
||||
|
||||
class QComboBox;
|
||||
class WebView;
|
||||
class TreeWidget;
|
||||
|
||||
class QT_QUPZILLA_EXPORT BookmarksTree : public TreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum BookmarkView {
|
||||
SideBarView,
|
||||
ManagerView,
|
||||
ComboFolderView, // I should found a better name ;)
|
||||
ExportFolderView // reserved for export functionality!
|
||||
};
|
||||
|
||||
BookmarksTree(QWidget* parent = 0);
|
||||
|
||||
BookmarksTree::BookmarkView viewType() {return m_viewType;}
|
||||
void setViewType(BookmarksTree::BookmarkView viewType);
|
||||
|
||||
protected:
|
||||
void drawBranches(QPainter* painter, const QRect &rect, const QModelIndex &index) const;
|
||||
|
||||
public slots:
|
||||
void refreshTree();
|
||||
void activeItemChange(int index, QComboBox* combo = 0, const QString &title = QString(), WebView* = 0);
|
||||
|
||||
private:
|
||||
BookmarkView m_viewType;
|
||||
|
||||
signals:
|
||||
void requestNewFolder(QWidget*,QString*,bool,QString,WebView*);
|
||||
};
|
||||
#endif // BOOKMARKSTREE_H
|
@ -23,6 +23,8 @@
|
||||
#include "speeddial.h"
|
||||
#include "webview.h"
|
||||
#include "qupzilla.h"
|
||||
#include "bookmarkstree.h"
|
||||
#include "browsinglibrary.h"
|
||||
|
||||
#include <QToolTip>
|
||||
#include <QSqlQuery>
|
||||
@ -41,6 +43,12 @@ BookmarksWidget::BookmarksWidget(QupZilla* mainClass, WebView* view, QWidget* pa
|
||||
, m_edited(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_bookmarksTree = new BookmarksTree(this);
|
||||
m_bookmarksTree->setViewType(BookmarksTree::ComboFolderView);
|
||||
m_bookmarksTree->header()->hide();
|
||||
m_bookmarksTree->setColumnCount(1);
|
||||
ui->folder->setModel(m_bookmarksTree->model());
|
||||
ui->folder->setView(m_bookmarksTree);
|
||||
|
||||
// The locationbar's direction is direction of its text,
|
||||
// it dynamically changes and so, it's not good choice for this widget.
|
||||
@ -54,26 +62,37 @@ BookmarksWidget::BookmarksWidget(QupZilla* mainClass, WebView* view, QWidget* pa
|
||||
tr("Remove from Speed Dial"));
|
||||
|
||||
loadBookmark();
|
||||
|
||||
connect(ui->folder, SIGNAL(activated(int)), this, SLOT(comboItemActive(int)));
|
||||
connect(m_bookmarksTree, SIGNAL(requestNewFolder(QWidget*,QString*,bool,QString,WebView*)),
|
||||
reinterpret_cast<QObject*>(mApp->browsingLibrary()->bookmarksManager()), SLOT(addFolder(QWidget*,QString*,bool,QString,WebView*)));
|
||||
}
|
||||
|
||||
void BookmarksWidget::loadBookmark()
|
||||
{
|
||||
// Bookmark folders
|
||||
ui->folder->addItem(QIcon(":/icons/other/unsortedbookmarks.png"), _bookmarksUnsorted, "unsorted");
|
||||
ui->folder->addItem(style()->standardIcon(QStyle::SP_DirOpenIcon), _bookmarksMenu, "bookmarksMenu");
|
||||
ui->folder->addItem(style()->standardIcon(QStyle::SP_DirOpenIcon), _bookmarksToolbar, "bookmarksToolbar");
|
||||
QSqlQuery query;
|
||||
query.exec("SELECT name FROM folders");
|
||||
while (query.next()) {
|
||||
ui->folder->addItem(style()->standardIcon(QStyle::SP_DirIcon), query.value(0).toString(), query.value(0).toString());
|
||||
}
|
||||
m_bookmarksTree->refreshTree();
|
||||
|
||||
m_bookmarkId = m_bookmarksModel->bookmarkId(m_url);
|
||||
|
||||
if (m_bookmarkId > 0) {
|
||||
BookmarksModel::Bookmark bookmark = m_bookmarksModel->getBookmark(m_bookmarkId);
|
||||
ui->name->setText(bookmark.title);
|
||||
ui->folder->setCurrentIndex(ui->folder->findData(bookmark.folder));
|
||||
|
||||
int index = ui->folder->findData(bookmark.folder);
|
||||
// QComboBox::findData() returns index related to the item's parent
|
||||
if (index == -1) { // subfolder
|
||||
QModelIndex rootIndex = ui->folder->rootModelIndex();
|
||||
ui->folder->setRootModelIndex(ui->folder->model()->index(ui->folder->findText(_bookmarksToolbar),0));
|
||||
// subfolder's name and its stored data are the same
|
||||
index = ui->folder->findText(bookmark.folder);
|
||||
ui->folder->setCurrentIndex(index);
|
||||
ui->folder->setRootModelIndex(rootIndex);
|
||||
}
|
||||
else {
|
||||
ui->folder->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
ui->saveRemove->setText(tr("Remove"));
|
||||
connect(ui->name, SIGNAL(textEdited(QString)), SLOT(bookmarkEdited()));
|
||||
connect(ui->folder, SIGNAL(currentIndexChanged(int)), SLOT(bookmarkEdited()));
|
||||
@ -111,11 +130,16 @@ void BookmarksWidget::bookmarkEdited()
|
||||
ui->saveRemove->setText(tr("Save"));
|
||||
}
|
||||
|
||||
void BookmarksWidget::comboItemActive(int index)
|
||||
{
|
||||
m_bookmarksTree->activeItemChange(index, ui->folder, ui->name->text(), m_view);
|
||||
}
|
||||
|
||||
void BookmarksWidget::on_saveRemove_clicked(bool)
|
||||
{
|
||||
if (m_bookmarkId > 0) {
|
||||
if (m_edited) {
|
||||
m_bookmarksModel->editBookmark(m_bookmarkId, ui->name->text(), QUrl(), ui->folder->itemData(ui->folder->currentIndex()).toString());
|
||||
m_bookmarksModel->editBookmark(m_bookmarkId, ui->name->text(), QUrl(), BookmarksModel::fromTranslatedFolder(ui->folder->currentText()));
|
||||
}
|
||||
else {
|
||||
m_bookmarksModel->removeBookmark(m_url);
|
||||
@ -123,7 +147,7 @@ void BookmarksWidget::on_saveRemove_clicked(bool)
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_bookmarksModel->saveBookmark(m_url, ui->name->text(), m_view->icon(), ui->folder->currentText());
|
||||
m_bookmarksModel->saveBookmark(m_url, ui->name->text(), m_view->icon(), BookmarksModel::fromTranslatedFolder(ui->folder->currentText()));
|
||||
}
|
||||
QTimer::singleShot(HIDE_DELAY, this, SLOT(close()));
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ class WebView;
|
||||
class SpeedDial;
|
||||
class BookmarksModel;
|
||||
class QupZilla;
|
||||
class BookmarksTree;
|
||||
|
||||
class QT_QUPZILLA_EXPORT BookmarksWidget : public LocationBarPopup
|
||||
{
|
||||
@ -47,6 +48,7 @@ signals:
|
||||
private slots:
|
||||
void on_saveRemove_clicked(bool);
|
||||
void bookmarkEdited();
|
||||
void comboItemActive(int index);
|
||||
|
||||
void toggleSpeedDial();
|
||||
|
||||
@ -62,6 +64,7 @@ private:
|
||||
BookmarksModel* m_bookmarksModel;
|
||||
SpeedDial* m_speedDial;
|
||||
bool m_edited;
|
||||
BookmarksTree* m_bookmarksTree;
|
||||
};
|
||||
|
||||
#endif // BOOKMARKSWIDGET_H
|
||||
|
@ -196,7 +196,8 @@ SOURCES += \
|
||||
network/schemehandlers/adblockschemehandler.cpp \
|
||||
network/schemehandlers/fileschemehandler.cpp \
|
||||
other/registerqappassociation.cpp \
|
||||
tools/listitemdelegate.cpp
|
||||
tools/listitemdelegate.cpp \
|
||||
bookmarks/bookmarkstree.cpp
|
||||
|
||||
HEADERS += \
|
||||
webview/tabpreview.h \
|
||||
@ -355,7 +356,8 @@ HEADERS += \
|
||||
network/schemehandlers/adblockschemehandler.h \
|
||||
network/schemehandlers/fileschemehandler.h \
|
||||
other/registerqappassociation.h \
|
||||
tools/listitemdelegate.h
|
||||
tools/listitemdelegate.h \
|
||||
bookmarks/bookmarkstree.h
|
||||
|
||||
FORMS += \
|
||||
preferences/autofillmanager.ui \
|
||||
|
@ -40,6 +40,7 @@ BookmarksSideBar::BookmarksSideBar(QupZilla* mainClass, QWidget* parent)
|
||||
, m_bookmarksModel(mApp->bookmarksModel())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->bookmarksTree->setViewType(BookmarksTree::SideBarView);
|
||||
|
||||
ui->bookmarksTree->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
ui->bookmarksTree->setDragDropReceiver(true, m_bookmarksModel);
|
||||
@ -335,65 +336,7 @@ void BookmarksSideBar::keyPressEvent(QKeyEvent* event)
|
||||
void BookmarksSideBar::refreshTable()
|
||||
{
|
||||
m_isRefreshing = true;
|
||||
ui->bookmarksTree->setUpdatesEnabled(false);
|
||||
ui->bookmarksTree->clear();
|
||||
|
||||
QSqlQuery query;
|
||||
QTreeWidgetItem* newItem = new QTreeWidgetItem(ui->bookmarksTree);
|
||||
newItem->setText(0, _bookmarksMenu);
|
||||
newItem->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
newItem->setFlags((newItem->flags() & ~Qt::ItemIsDragEnabled) | Qt::ItemIsDropEnabled);
|
||||
ui->bookmarksTree->addTopLevelItem(newItem);
|
||||
|
||||
query.exec("SELECT name FROM folders WHERE subfolder!='yes'");
|
||||
while (query.next()) {
|
||||
newItem = new QTreeWidgetItem(ui->bookmarksTree);
|
||||
newItem->setText(0, query.value(0).toString());
|
||||
newItem->setIcon(0, style()->standardIcon(QStyle::SP_DirIcon));
|
||||
newItem->setFlags(newItem->flags() | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
ui->bookmarksTree->addTopLevelItem(newItem);
|
||||
}
|
||||
|
||||
query.exec("SELECT title, url, id, folder, icon FROM bookmarks");
|
||||
while (query.next()) {
|
||||
QString title = query.value(0).toString();
|
||||
QUrl url = query.value(1).toUrl();
|
||||
int id = query.value(2).toInt();
|
||||
QString folder = query.value(3).toString();
|
||||
QIcon icon = qIconProvider->iconFromImage(QImage::fromData(query.value(4).toByteArray()));
|
||||
QTreeWidgetItem* item;
|
||||
if (folder == QLatin1String("bookmarksMenu")) {
|
||||
folder = _bookmarksMenu;
|
||||
}
|
||||
if (folder == QLatin1String("bookmarksToolbar")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (folder != QLatin1String("unsorted")) {
|
||||
QList<QTreeWidgetItem*> findParent = ui->bookmarksTree->findItems(folder, 0);
|
||||
if (findParent.count() != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item = new QTreeWidgetItem(findParent.at(0));
|
||||
|
||||
}
|
||||
else {
|
||||
item = new QTreeWidgetItem(ui->bookmarksTree);
|
||||
}
|
||||
|
||||
item->setText(0, title);
|
||||
item->setText(1, url.toEncoded());
|
||||
item->setToolTip(0, url.toEncoded());
|
||||
|
||||
item->setData(0, Qt::UserRole + 10, id);
|
||||
item->setIcon(0, icon);
|
||||
item->setFlags(item->flags() | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
ui->bookmarksTree->addTopLevelItem(item);
|
||||
}
|
||||
ui->bookmarksTree->expandAll();
|
||||
|
||||
ui->bookmarksTree->setUpdatesEnabled(true);
|
||||
ui->bookmarksTree->refreshTree();
|
||||
m_isRefreshing = false;
|
||||
|
||||
ui->search->setFocus();
|
||||
|
@ -34,7 +34,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="TreeWidget" name="bookmarksTree">
|
||||
<widget class="BookmarksTree" name="bookmarksTree">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
@ -61,9 +61,9 @@
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>TreeWidget</class>
|
||||
<class>BookmarksTree</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>treewidget.h</header>
|
||||
<header>bookmarkstree.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
|
Loading…
Reference in New Issue
Block a user