Import TabManager plugin from qupzilla-plugins
11
src/plugins/TabManager/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
TabManager extension for QupZilla
|
||||
-------------------------------------------------
|
||||
This extension adds the ability to manage tabs and windows in QupZilla.
|
||||
|
||||
![tbm3](http://i.imgur.com/Gh8bEXo.png)
|
||||
|
||||
You will find more information about the configuration and usage of this extension in the [wiki](https://github.com/QupZilla/qupzilla-plugins/wiki/Tab-Manager).
|
||||
|
||||
**TODOs**
|
||||
|
||||
* Modifying `refresh` algorithm for updating changed items and not all items.
|
30
src/plugins/TabManager/TabManager.pro
Normal file
@ -0,0 +1,30 @@
|
||||
TARGET = $$qtLibraryTarget(TabManager)
|
||||
# OS/2 allows only 8 chars in TARGET
|
||||
os2: TARGET = TabManPl
|
||||
|
||||
SOURCES += tabmanagerplugin.cpp \
|
||||
tabmanagerwidget.cpp \
|
||||
tabmanagerwidgetcontroller.cpp
|
||||
|
||||
HEADERS += tabmanagerplugin.h \
|
||||
tabmanagerwidget.h \
|
||||
tabmanagerwidgetcontroller.h
|
||||
|
||||
RESOURCES += tabmanagerplugin.qrc
|
||||
|
||||
FORMS += \
|
||||
tabmanagerwidget.ui
|
||||
|
||||
TRANSLATIONS = \
|
||||
translations/fa_IR.ts
|
||||
|
||||
include(tldextractor/tldextractor.pri)
|
||||
|
||||
PLUGIN_DIR = $$PWD
|
||||
srcdir = $$(QUPZILLA_SRCDIR)
|
||||
equals(srcdir, "") {
|
||||
include(../../plugins.pri)
|
||||
}
|
||||
else {
|
||||
include($$srcdir/src/plugins.pri)
|
||||
}
|
BIN
src/plugins/TabManager/data/side-by-side.png
Normal file
After Width: | Height: | Size: 939 B |
BIN
src/plugins/TabManager/data/tab-bookmark.png
Normal file
After Width: | Height: | Size: 807 B |
BIN
src/plugins/TabManager/data/tab-close.png
Normal file
After Width: | Height: | Size: 976 B |
BIN
src/plugins/TabManager/data/tab-detach.png
Normal file
After Width: | Height: | Size: 784 B |
BIN
src/plugins/TabManager/data/tab-loading.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/plugins/TabManager/data/tab-pinned.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/plugins/TabManager/data/tabmanager.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
183
src/plugins/TabManager/tabmanagerplugin.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/* ============================================================
|
||||
* TabManager plugin for QupZilla
|
||||
* Copyright (C) 2013 S. Razi Alavizadeh <s.r.alavizadeh@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 "tabmanagerplugin.h"
|
||||
#include "tabmanagerwidgetcontroller.h"
|
||||
#include "tabmanagerwidget.h"
|
||||
#include "browserwindow.h"
|
||||
#include "pluginproxy.h"
|
||||
#include "mainapplication.h"
|
||||
#include "sidebar.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QTranslator>
|
||||
#include <QSettings>
|
||||
#include <QAction>
|
||||
#include <QTimer>
|
||||
|
||||
QString TabManagerPlugin::s_settingsPath;
|
||||
|
||||
TabManagerPlugin::TabManagerPlugin()
|
||||
: QObject()
|
||||
, m_controller(0)
|
||||
, m_tabManagerWidget(0)
|
||||
, m_initState(false)
|
||||
{
|
||||
}
|
||||
|
||||
PluginSpec TabManagerPlugin::pluginSpec()
|
||||
{
|
||||
PluginSpec spec;
|
||||
spec.name = "Tab Manager";
|
||||
spec.info = "Simple yet powerful tab manager for QupZilla";
|
||||
spec.description = "Adds ability to managing tabs and windows";
|
||||
spec.version = "0.4.1";
|
||||
spec.author = "Razi Alavizadeh <s.r.alavizadeh@gmail.com>";
|
||||
spec.icon = QPixmap(":tabmanager/data/tabmanager.png");
|
||||
spec.hasSettings = true;
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
void TabManagerPlugin::init(InitState state, const QString &settingsPath)
|
||||
{
|
||||
Q_UNUSED(state)
|
||||
|
||||
m_controller = new TabManagerWidgetController(this);
|
||||
connect(mApp->plugins(), SIGNAL(mainWindowCreated(BrowserWindow*)), m_controller, SLOT(mainWindowCreated(BrowserWindow*)));
|
||||
connect(mApp->plugins(), SIGNAL(mainWindowDeleted(BrowserWindow*)), m_controller, SLOT(mainWindowDeleted(BrowserWindow*)));
|
||||
connect(mApp->plugins(), SIGNAL(webPageCreated(WebPage*)), m_controller, SIGNAL(requestRefreshTree()));
|
||||
connect(mApp->plugins(), SIGNAL(webPageDeleted(WebPage*)), m_controller, SIGNAL(requestRefreshTree(WebPage*)));
|
||||
|
||||
s_settingsPath = settingsPath + QL1S("/TabManager");
|
||||
m_initState = true;
|
||||
|
||||
// load settings
|
||||
QSettings settings(s_settingsPath + QL1S("/tabmanager.ini"), QSettings::IniFormat);
|
||||
settings.beginGroup("View");
|
||||
m_controller->setGroupType(TabManagerWidget::GroupType(settings.value("GroupType", TabManagerWidget::GroupByWindow).toInt()));
|
||||
m_controller->setViewType(TabManagerWidgetController::ViewType(settings.value("ViewType", TabManagerWidgetController::ShowAsWindow).toInt()));
|
||||
settings.endGroup();
|
||||
|
||||
insertManagerWidget();
|
||||
}
|
||||
|
||||
void TabManagerPlugin::unload()
|
||||
{
|
||||
// save settings
|
||||
QSettings settings(s_settingsPath + QL1S("/tabmanager.ini"), QSettings::IniFormat);
|
||||
settings.beginGroup("View");
|
||||
settings.setValue("GroupType", m_controller->groupType());
|
||||
settings.setValue("ViewType", m_controller->viewType());
|
||||
settings.endGroup();
|
||||
|
||||
removeManagerWidget();
|
||||
|
||||
delete m_controller;
|
||||
}
|
||||
|
||||
bool TabManagerPlugin::testPlugin()
|
||||
{
|
||||
return (Qz::VERSION == QLatin1String(QUPZILLA_VERSION));
|
||||
}
|
||||
|
||||
QTranslator* TabManagerPlugin::getTranslator(const QString &locale)
|
||||
{
|
||||
QTranslator* translator = new QTranslator(this);
|
||||
translator->load(locale, ":/tabmanager/locale/");
|
||||
return translator;
|
||||
}
|
||||
|
||||
void TabManagerPlugin::showSettings(QWidget* parent)
|
||||
{
|
||||
bool ok;
|
||||
QString viewType = QInputDialog::getItem(parent, tr("Tab Manager View Type"),
|
||||
tr("<p>Please select view type:<br />"
|
||||
"<b>Note:</b> The \"<i>Window</i>\" type is recommended for managing lots of windows/tabs")
|
||||
, QStringList() << tr("SideBar") << tr("Window")
|
||||
, m_controller->viewType(), false, &ok, Qt::WindowStaysOnTopHint);
|
||||
TabManagerWidgetController::ViewType type;
|
||||
if (viewType == tr("SideBar")) {
|
||||
type = TabManagerWidgetController::ShowAsSideBar;
|
||||
}
|
||||
else {
|
||||
type = TabManagerWidgetController::ShowAsWindow;
|
||||
}
|
||||
|
||||
if (ok && type != m_controller->viewType()) {
|
||||
removeManagerWidget();
|
||||
m_controller->setViewType(type);
|
||||
insertManagerWidget();
|
||||
|
||||
if (type == TabManagerWidgetController::ShowAsSideBar) {
|
||||
mApp->getWindow()->sideBarManager()->showSideBar("TabManager");
|
||||
}
|
||||
else if (type == TabManagerWidgetController::ShowAsWindow) {
|
||||
// add statusbar icon
|
||||
foreach (BrowserWindow* window, mApp->windows()) {
|
||||
m_controller->addStatusBarIcon(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerPlugin::insertManagerWidget()
|
||||
{
|
||||
if (m_controller->viewType() == TabManagerWidgetController::ShowAsSideBar) {
|
||||
SideBarManager::addSidebar("TabManager", m_controller);
|
||||
}
|
||||
else if (m_controller->viewType() == TabManagerWidgetController::ShowAsWindow) {
|
||||
if (!m_tabManagerWidget) {
|
||||
m_tabManagerWidget = m_controller->createTabManagerWidget(mApp->getWindow(), 0, true);
|
||||
m_tabManagerWidget->setWindowFlags(Qt::Window);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_initState) {
|
||||
foreach (BrowserWindow* window, mApp->windows()) {
|
||||
m_controller->mainWindowCreated(window, false);
|
||||
}
|
||||
|
||||
m_initState = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerPlugin::removeManagerWidget()
|
||||
{
|
||||
if (m_controller->viewType() == TabManagerWidgetController::ShowAsSideBar) {
|
||||
SideBarManager::removeSidebar("TabManager");
|
||||
}
|
||||
else if (m_controller->viewType() == TabManagerWidgetController::ShowAsWindow) {
|
||||
// remove statusbar icon
|
||||
foreach (BrowserWindow* window, mApp->windows()) {
|
||||
m_controller->removeStatusBarIcon(window);
|
||||
}
|
||||
|
||||
m_tabManagerWidget->close();
|
||||
delete m_tabManagerWidget;
|
||||
m_tabManagerWidget = 0;
|
||||
}
|
||||
}
|
||||
|
||||
QString TabManagerPlugin::settingsPath()
|
||||
{
|
||||
return s_settingsPath;
|
||||
}
|
||||
|
||||
#if QT_VERSION < 0x050000
|
||||
Q_EXPORT_PLUGIN2(TabManager, TabManagerPlugin)
|
||||
#endif
|
69
src/plugins/TabManager/tabmanagerplugin.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* ============================================================
|
||||
* TabManager plugin for QupZilla
|
||||
* Copyright (C) 2013 S. Razi Alavizadeh <s.r.alavizadeh@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 TABMANAGERPLUGIN_H
|
||||
#define TABMANAGERPLUGIN_H
|
||||
|
||||
|
||||
#include "plugininterface.h"
|
||||
#include "tabmanagerwidgetcontroller.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QWebElement>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPointer>
|
||||
|
||||
class TabManagerWidget;
|
||||
|
||||
class TabManagerPlugin : public QObject, public PluginInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(PluginInterface)
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
Q_PLUGIN_METADATA(IID "QupZilla.Browser.plugin.TabManagerPlugin")
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit TabManagerPlugin();
|
||||
PluginSpec pluginSpec();
|
||||
|
||||
void init(InitState state, const QString &settingsPath);
|
||||
void unload();
|
||||
bool testPlugin();
|
||||
|
||||
QTranslator* getTranslator(const QString &locale);
|
||||
void showSettings(QWidget* parent = 0);
|
||||
|
||||
void removeManagerWidget();
|
||||
|
||||
static QString settingsPath();
|
||||
|
||||
public slots:
|
||||
void insertManagerWidget();
|
||||
|
||||
private:
|
||||
TabManagerWidgetController* m_controller;
|
||||
TabManagerWidget* m_tabManagerWidget;
|
||||
static QString s_settingsPath;
|
||||
QString m_viewType;
|
||||
bool m_initState;
|
||||
};
|
||||
|
||||
#endif // TABMANAGERPLUGIN_H
|
12
src/plugins/TabManager/tabmanagerplugin.qrc
Normal file
@ -0,0 +1,12 @@
|
||||
<RCC>
|
||||
<qresource prefix="/tabmanager">
|
||||
<file>data/tabmanager.png</file>
|
||||
<file>data/tab-close.png</file>
|
||||
<file>data/tab-bookmark.png</file>
|
||||
<file>data/tab-detach.png</file>
|
||||
<file>data/tab-loading.png</file>
|
||||
<file>data/tab-pinned.png</file>
|
||||
<file>data/side-by-side.png</file>
|
||||
<file>locale/fa_IR.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
595
src/plugins/TabManager/tabmanagerwidget.cpp
Normal file
@ -0,0 +1,595 @@
|
||||
/* ============================================================
|
||||
* TabManager plugin for QupZilla
|
||||
* Copyright (C) 2013 S. Razi Alavizadeh <s.r.alavizadeh@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 "tabmanagerwidget.h"
|
||||
#include "ui_tabmanagerwidget.h"
|
||||
#include "mainapplication.h"
|
||||
#include "browserwindow.h"
|
||||
#include "webtab.h"
|
||||
#include "webpage.h"
|
||||
#include "tabbedwebview.h"
|
||||
#include "tabwidget.h"
|
||||
#include "locationbar.h"
|
||||
#include "bookmarkstools.h"
|
||||
#include "bookmarkitem.h"
|
||||
#include "bookmarks.h"
|
||||
#include "tabmanagerplugin.h"
|
||||
#include "tldextractor/tldextractor.h"
|
||||
|
||||
|
||||
#include <QDesktopWidget>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QStackedWidget>
|
||||
#include <QDialog>
|
||||
#include <QTimer>
|
||||
#include <QLabel>
|
||||
|
||||
#define WebTabPointerRole Qt::UserRole + 10
|
||||
#define QupZillaPointerRole Qt::UserRole + 20
|
||||
|
||||
TLDExtractor* TabManagerWidget::s_tldExtractor = 0;
|
||||
|
||||
TabManagerWidget::TabManagerWidget(BrowserWindow* mainClass, QWidget* parent, bool defaultWidget)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::TabManagerWidget)
|
||||
, p_QupZilla(mainClass)
|
||||
, m_webPage(0)
|
||||
, m_isRefreshing(false)
|
||||
, m_refreshBlocked(false)
|
||||
, m_waitForRefresh(false)
|
||||
, m_isDefaultWidget(defaultWidget)
|
||||
{
|
||||
if(s_tldExtractor == 0)
|
||||
{
|
||||
s_tldExtractor = TLDExtractor::instance();
|
||||
s_tldExtractor->setDataSearchPaths(QStringList() << TabManagerPlugin::settingsPath());
|
||||
}
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->treeWidget->setExpandsOnDoubleClick(false);
|
||||
ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(ui->treeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(itemDoubleClick(QTreeWidgetItem*,int)));
|
||||
connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint)));
|
||||
}
|
||||
|
||||
TabManagerWidget::~TabManagerWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void TabManagerWidget::setGroupType(GroupType type)
|
||||
{
|
||||
m_groupType = type;
|
||||
}
|
||||
|
||||
QString TabManagerWidget::domainFromUrl(const QUrl &url, bool useHostName)
|
||||
{
|
||||
QString appendString = QL1S(":");
|
||||
QString urlString = url.toString();
|
||||
|
||||
if (url.scheme() == "file") {
|
||||
return tr("Local File System:");
|
||||
}
|
||||
else if (url.scheme() == "qupzilla" || urlString.isEmpty()) {
|
||||
return tr("QupZilla:");
|
||||
}
|
||||
else if (url.scheme() == "ftp") {
|
||||
appendString.prepend(tr(" [FTP]"));
|
||||
}
|
||||
|
||||
QString host = url.host();
|
||||
if (host.isEmpty()) {
|
||||
return urlString.append(appendString);
|
||||
}
|
||||
|
||||
if (useHostName || host.contains(QRegExp("^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$"))) {
|
||||
if (host.startsWith("www.", Qt::CaseInsensitive)) {
|
||||
host.remove(0, 4);
|
||||
}
|
||||
|
||||
return host.append(appendString);
|
||||
}
|
||||
else {
|
||||
const QString registeredDomain = s_tldExtractor->registrableDomain(host);
|
||||
|
||||
if (!registeredDomain.isEmpty()) {
|
||||
host = registeredDomain;
|
||||
}
|
||||
|
||||
return host.append(appendString);
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerWidget::delayedRefreshTree(WebPage* p)
|
||||
{
|
||||
if (m_refreshBlocked || m_waitForRefresh) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_isRefreshing && !p) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_webPage = p;
|
||||
m_waitForRefresh = true;
|
||||
QTimer::singleShot(50, this, SLOT(refreshTree()));
|
||||
}
|
||||
|
||||
void TabManagerWidget::refreshTree()
|
||||
{
|
||||
if (m_refreshBlocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_isRefreshing && !m_webPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
// store selected items
|
||||
QList<QWidget*> selectedTabs;
|
||||
for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem* winItem = ui->treeWidget->topLevelItem(i);
|
||||
if (winItem->checkState(0) == Qt::Unchecked) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < winItem->childCount(); ++j) {
|
||||
QTreeWidgetItem* tabItem = winItem->child(j);
|
||||
if (tabItem->checkState(0) == Qt::Unchecked) {
|
||||
continue;
|
||||
}
|
||||
selectedTabs << qvariant_cast<QWidget*>(tabItem->data(0, WebTabPointerRole));
|
||||
}
|
||||
}
|
||||
|
||||
ui->treeWidget->clear();
|
||||
|
||||
if (m_groupType == GroupByHost) {
|
||||
groupByDomainName(true);
|
||||
}
|
||||
else if (m_groupType == GroupByDomain) {
|
||||
groupByDomainName();
|
||||
}
|
||||
else { // fallback to GroupByWindow
|
||||
m_groupType = GroupByWindow;
|
||||
groupByWindow();
|
||||
}
|
||||
|
||||
// restore selected items
|
||||
for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem* winItem = ui->treeWidget->topLevelItem(i);
|
||||
|
||||
for (int j = 0; j < winItem->childCount(); ++j) {
|
||||
QTreeWidgetItem* tabItem = winItem->child(j);
|
||||
|
||||
if (selectedTabs.contains(qvariant_cast<QWidget*>(tabItem->data(0, WebTabPointerRole)))) {
|
||||
tabItem->setCheckState(0, Qt::Checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui->treeWidget->expandAll();
|
||||
m_isRefreshing = false;
|
||||
m_waitForRefresh = false;
|
||||
}
|
||||
|
||||
void TabManagerWidget::itemDoubleClick(QTreeWidgetItem* item, int)
|
||||
{
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrowserWindow* mainWindow = qobject_cast<BrowserWindow*>(qvariant_cast<QWidget*>(item->data(0, QupZillaPointerRole)));
|
||||
QWidget* tabWidget = qvariant_cast<QWidget*>(item->data(0, WebTabPointerRole));
|
||||
|
||||
if (!mainWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mainWindow->isMinimized()) {
|
||||
mainWindow->showNormal();
|
||||
}
|
||||
else {
|
||||
mainWindow->show();
|
||||
}
|
||||
mainWindow->activateWindow();
|
||||
mainWindow->raise();
|
||||
mainWindow->weView()->setFocus();
|
||||
|
||||
if (tabWidget && tabWidget != mainWindow->tabWidget()->currentWidget()) {
|
||||
mainWindow->tabWidget()->setCurrentIndex(mainWindow->tabWidget()->indexOf(tabWidget));
|
||||
}
|
||||
}
|
||||
|
||||
bool TabManagerWidget::isTabSelected()
|
||||
{
|
||||
bool selected = false;
|
||||
for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(i);
|
||||
if (parentItem->checkState(0) != Qt::Unchecked) {
|
||||
selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
void TabManagerWidget::customContextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
QMenu menu;
|
||||
QAction* action;
|
||||
QMenu groupTypeSubmenu(tr("Group by"));
|
||||
action = groupTypeSubmenu.addAction(tr("&Window"), this, SLOT(changeGroupType()));
|
||||
action->setData(GroupByWindow);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(m_groupType == GroupByWindow);
|
||||
|
||||
action = groupTypeSubmenu.addAction(tr("&Domain"), this, SLOT(changeGroupType()));
|
||||
action->setData(GroupByDomain);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(m_groupType == GroupByDomain);
|
||||
|
||||
action = groupTypeSubmenu.addAction(tr("&Host"), this, SLOT(changeGroupType()));
|
||||
action->setData(GroupByHost);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(m_groupType == GroupByHost);
|
||||
|
||||
menu.addMenu(&groupTypeSubmenu);
|
||||
|
||||
if (m_isDefaultWidget) {
|
||||
menu.addAction(QIcon(":/tabmanager/data/side-by-side.png"), tr("&Show side by side"), this, SIGNAL(showSideBySide()))->setObjectName("sideBySide");
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
if (isTabSelected()) {
|
||||
menu.addAction(QIcon(":/tabmanager/data/tab-detach.png"), tr("&Detach checked tabs"), this, SLOT(processActions()))->setObjectName("detachSelection");
|
||||
menu.addAction(QIcon(":/tabmanager/data/tab-bookmark.png"), tr("Book&mark checked tabs"), this, SLOT(processActions()))->setObjectName("bookmarkSelection");
|
||||
menu.addAction(QIcon(":/tabmanager/data/tab-close.png"), tr("&Close checked tabs"), this, SLOT(processActions()))->setObjectName("closeSelection");
|
||||
}
|
||||
|
||||
menu.exec(ui->treeWidget->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void TabManagerWidget::processActions()
|
||||
{
|
||||
if (!sender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_refreshBlocked = true;
|
||||
|
||||
QHash<BrowserWindow*, WebTab*> selectedTabs;
|
||||
|
||||
const QString &command = sender()->objectName();
|
||||
|
||||
for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem* winItem = ui->treeWidget->topLevelItem(i);
|
||||
if (winItem->checkState(0) == Qt::Unchecked) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < winItem->childCount(); ++j) {
|
||||
QTreeWidgetItem* tabItem = winItem->child(j);
|
||||
if (tabItem->checkState(0) == Qt::Unchecked) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BrowserWindow* mainWindow = qobject_cast<BrowserWindow*>(qvariant_cast<QWidget*>(tabItem->data(0, QupZillaPointerRole)));
|
||||
WebTab* webTab = qobject_cast<WebTab*>(qvariant_cast<QWidget*>(tabItem->data(0, WebTabPointerRole)));
|
||||
|
||||
// current supported actions are not applied to pinned tabs
|
||||
if (webTab->isPinned()) {
|
||||
tabItem->setCheckState(0, Qt::Unchecked);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (command == "closeSelection") {
|
||||
if (webTab->url().toString() == "qupzilla:restore") {
|
||||
continue;
|
||||
}
|
||||
selectedTabs.insertMulti(mainWindow, webTab);
|
||||
}
|
||||
else if (command == "detachSelection" || command == "bookmarkSelection") {
|
||||
selectedTabs.insertMulti(mainWindow, webTab);
|
||||
}
|
||||
}
|
||||
winItem->setCheckState(0, Qt::Unchecked);
|
||||
}
|
||||
|
||||
if (!selectedTabs.isEmpty()) {
|
||||
if (command == "closeSelection") {
|
||||
closeSelectedTabs(selectedTabs);
|
||||
}
|
||||
else if (command == "detachSelection") {
|
||||
detachSelectedTabs(selectedTabs);
|
||||
}
|
||||
else if (command == "bookmarkSelection") {
|
||||
bookmarkSelectedTabs(selectedTabs);
|
||||
}
|
||||
}
|
||||
|
||||
m_refreshBlocked = false;
|
||||
delayedRefreshTree();
|
||||
}
|
||||
|
||||
void TabManagerWidget::changeGroupType()
|
||||
{
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
|
||||
if (action) {
|
||||
int type = action->data().toInt();
|
||||
|
||||
if (m_groupType != GroupType(type)) {
|
||||
m_groupType = GroupType(type);
|
||||
|
||||
delayedRefreshTree();
|
||||
|
||||
emit groupTypeChanged(m_groupType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerWidget::closeSelectedTabs(const QHash<BrowserWindow*, WebTab*> &tabsHash)
|
||||
{
|
||||
if (tabsHash.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QList<BrowserWindow*> &windows = tabsHash.uniqueKeys();
|
||||
foreach (BrowserWindow* mainWindow, windows) {
|
||||
QList<WebTab*> tabs = tabsHash.values(mainWindow);
|
||||
|
||||
foreach (WebTab* webTab, tabs) {
|
||||
mainWindow->tabWidget()->closeTab(webTab->tabIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerWidget::detachSelectedTabs(const QHash<BrowserWindow*, WebTab*> &tabsHash)
|
||||
{
|
||||
// TODO: use TabWidget::detachTab()
|
||||
if (tabsHash.isEmpty() ||
|
||||
(tabsHash.uniqueKeys().size() == 1 &&
|
||||
tabsHash.size() == tabsHash.keys().at(0)->tabWidget()->count())) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrowserWindow* newWindow = mApp->createWindow(Qz::BW_OtherRestoredWindow);;
|
||||
newWindow->move(mApp->desktop()->availableGeometry(this).topLeft() + QPoint(30, 30));
|
||||
|
||||
const QList<BrowserWindow*> &windows = tabsHash.uniqueKeys();
|
||||
foreach (BrowserWindow* mainWindow, windows) {
|
||||
const QList<WebTab*> &tabs = tabsHash.values(mainWindow);
|
||||
foreach (WebTab* webTab, tabs) {
|
||||
mainWindow->tabWidget()->locationBars()->removeWidget(webTab->locationBar());
|
||||
|
||||
disconnect(webTab->webView(), SIGNAL(wantsCloseTab(int)), mainWindow->tabWidget(), SLOT(closeTab(int)));
|
||||
disconnect(webTab->webView(), SIGNAL(changed()), mainWindow->tabWidget(), SIGNAL(changed()));
|
||||
disconnect(webTab->webView(), SIGNAL(ipChanged(QString)), mainWindow->ipLabel(), SLOT(setText(QString)));
|
||||
|
||||
webTab->detach();
|
||||
if (mainWindow && mainWindow->tabWidget()->count() == 0) {
|
||||
mainWindow->close();
|
||||
mainWindow = 0;
|
||||
}
|
||||
|
||||
newWindow->tabWidget()->addView(webTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TabManagerWidget::bookmarkSelectedTabs(const QHash<BrowserWindow*, WebTab*> &tabsHash)
|
||||
{
|
||||
QDialog* dialog = new QDialog(getQupZilla(), Qt::WindowStaysOnTopHint | Qt::MSWindowsFixedSizeDialogHint);
|
||||
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom, dialog);
|
||||
QLabel* label = new QLabel(dialog);
|
||||
BookmarksFoldersButton* folderButton = new BookmarksFoldersButton(dialog);
|
||||
|
||||
QDialogButtonBox* box = new QDialogButtonBox(dialog);
|
||||
box->addButton(QDialogButtonBox::Ok);
|
||||
box->addButton(QDialogButtonBox::Cancel);
|
||||
QObject::connect(box, SIGNAL(rejected()), dialog, SLOT(reject()));
|
||||
QObject::connect(box, SIGNAL(accepted()), dialog, SLOT(accept()));
|
||||
|
||||
layout->addWidget(label);
|
||||
layout->addWidget(folderButton);
|
||||
layout->addWidget(box);
|
||||
|
||||
label->setText(tr("Choose folder for bookmarks:"));
|
||||
dialog->setWindowTitle(tr("Bookmark Selected Tabs"));
|
||||
|
||||
QSize size = dialog->size();
|
||||
size.setWidth(350);
|
||||
dialog->resize(size);
|
||||
dialog->exec();
|
||||
|
||||
if (dialog->result() == QDialog::Rejected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (WebTab* tab, tabsHash) {
|
||||
if (!tab->url().isEmpty()) {
|
||||
BookmarkItem* bookmark = new BookmarkItem(BookmarkItem::Url);
|
||||
bookmark->setTitle(tab->title());
|
||||
bookmark->setUrl(tab->url());
|
||||
mApp->bookmarks()->addBookmark(folderButton->selectedFolder(), bookmark);
|
||||
}
|
||||
}
|
||||
|
||||
delete dialog;
|
||||
return true;
|
||||
}
|
||||
|
||||
QTreeWidgetItem* TabManagerWidget::createEmptyItem(QTreeWidgetItem* parent, bool addToTree)
|
||||
{
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem(addToTree ? (parent ? parent : ui->treeWidget->invisibleRootItem()) : 0);
|
||||
item->setFlags(item->flags() | (parent ? Qt::ItemIsUserCheckable : Qt::ItemIsUserCheckable | Qt::ItemIsTristate));
|
||||
item->setCheckState(0, Qt::Unchecked);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void TabManagerWidget::groupByDomainName(bool useHostName)
|
||||
{
|
||||
QList<BrowserWindow*> windows = mApp->windows();
|
||||
int currentWindowIdx = windows.indexOf(getQupZilla());
|
||||
if (currentWindowIdx == -1) {
|
||||
// getQupZilla() instance is closing
|
||||
return;
|
||||
}
|
||||
windows.move(currentWindowIdx, 0);
|
||||
|
||||
QMap<QString, QTreeWidgetItem*> tabsGroupedByDomain;
|
||||
|
||||
for (int win = 0; win < windows.count(); ++win) {
|
||||
BrowserWindow* mainWin = windows.at(win);
|
||||
|
||||
QList<WebTab*> tabs = mainWin->tabWidget()->allTabs();
|
||||
|
||||
for (int tab = 0; tab < tabs.count(); ++tab) {
|
||||
WebTab* webTab = tabs.at(tab);
|
||||
if (webTab->webView() && m_webPage == webTab->webView()->page()) {
|
||||
m_webPage = 0;
|
||||
continue;
|
||||
}
|
||||
QString domain = domainFromUrl(webTab->url(), useHostName);
|
||||
|
||||
if (!tabsGroupedByDomain.contains(domain)) {
|
||||
QTreeWidgetItem* groupItem = createEmptyItem(0, false);
|
||||
groupItem->setText(0, domain);
|
||||
groupItem->setToolTip(0, domain);
|
||||
QFont font = groupItem->font(0);
|
||||
font.setBold(true);
|
||||
groupItem->setFont(0, font);
|
||||
tabsGroupedByDomain.insert(domain, groupItem);
|
||||
}
|
||||
QTreeWidgetItem* groupItem = tabsGroupedByDomain.value(domain);
|
||||
|
||||
QTreeWidgetItem* tabItem = createEmptyItem(groupItem);
|
||||
if (webTab == mainWin->weView()->webTab()) {
|
||||
QFont font = tabItem->font(0);
|
||||
font.setBold(true);
|
||||
tabItem->setFont(0, font);
|
||||
}
|
||||
if (!webTab->isLoading()) {
|
||||
if (!webTab->isPinned()) {
|
||||
tabItem->setIcon(0, webTab->icon());
|
||||
}
|
||||
else {
|
||||
tabItem->setIcon(0, QIcon(":tabmanager/data/tab-pinned.png"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
tabItem->setIcon(0, QIcon(":tabmanager/data/tab-loading.png"));
|
||||
}
|
||||
tabItem->setText(0, webTab->title());
|
||||
tabItem->setToolTip(0, webTab->title());
|
||||
|
||||
tabItem->setData(0, WebTabPointerRole, QVariant::fromValue(qobject_cast<QWidget*>(webTab)));
|
||||
tabItem->setData(0, QupZillaPointerRole, QVariant::fromValue(qobject_cast<QWidget*>(mainWin)));
|
||||
|
||||
makeWebViewConnections(webTab->webView());
|
||||
}
|
||||
}
|
||||
|
||||
ui->treeWidget->insertTopLevelItems(0, tabsGroupedByDomain.values());
|
||||
}
|
||||
|
||||
void TabManagerWidget::groupByWindow()
|
||||
{
|
||||
QList<BrowserWindow*> windows = mApp->windows();
|
||||
int currentWindowIdx = windows.indexOf(getQupZilla());
|
||||
if (currentWindowIdx == -1) {
|
||||
return;
|
||||
}
|
||||
m_isRefreshing = true;
|
||||
|
||||
if (!m_isDefaultWidget) {
|
||||
windows.move(currentWindowIdx, 0);
|
||||
currentWindowIdx = 0;
|
||||
}
|
||||
|
||||
for (int win = 0; win < windows.count(); ++win) {
|
||||
BrowserWindow* mainWin = windows.at(win);
|
||||
QTreeWidgetItem* winItem = createEmptyItem();
|
||||
winItem->setText(0, tr("Window %1").arg(QString::number(win + 1)));
|
||||
winItem->setToolTip(0, tr("Double click to switch"));
|
||||
if (win == currentWindowIdx) {
|
||||
QFont font = winItem->font(0);
|
||||
font.setBold(true);
|
||||
winItem->setFont(0, font);
|
||||
}
|
||||
|
||||
winItem->setData(0, QupZillaPointerRole, QVariant::fromValue(qobject_cast<QWidget*>(mainWin)));
|
||||
QList<WebTab*> tabs = mainWin->tabWidget()->allTabs();
|
||||
|
||||
for (int tab = 0; tab < tabs.count(); ++tab) {
|
||||
WebTab* webTab = tabs.at(tab);
|
||||
if (webTab->webView() && m_webPage == webTab->webView()->page()) {
|
||||
m_webPage = 0;
|
||||
continue;
|
||||
}
|
||||
QTreeWidgetItem* tabItem = createEmptyItem(winItem);
|
||||
if (webTab == mainWin->weView()->webTab()) {
|
||||
QFont font = tabItem->font(0);
|
||||
font.setBold(true);
|
||||
tabItem->setFont(0, font);
|
||||
}
|
||||
if (!webTab->isLoading()) {
|
||||
if (!webTab->isPinned()) {
|
||||
tabItem->setIcon(0, webTab->icon());
|
||||
}
|
||||
else {
|
||||
tabItem->setIcon(0, QIcon(":tabmanager/data/tab-pinned.png"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
tabItem->setIcon(0, QIcon(":tabmanager/data/tab-loading.png"));
|
||||
}
|
||||
tabItem->setText(0, webTab->title());
|
||||
tabItem->setToolTip(0, webTab->title());
|
||||
|
||||
tabItem->setData(0, WebTabPointerRole, QVariant::fromValue(qobject_cast<QWidget*>(webTab)));
|
||||
tabItem->setData(0, QupZillaPointerRole, QVariant::fromValue(qobject_cast<QWidget*>(mainWin)));
|
||||
|
||||
makeWebViewConnections(webTab->webView());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BrowserWindow* TabManagerWidget::getQupZilla()
|
||||
{
|
||||
if (m_isDefaultWidget || !p_QupZilla) {
|
||||
return mApp->getWindow();
|
||||
}
|
||||
else {
|
||||
return p_QupZilla.data();
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerWidget::makeWebViewConnections(QWebView* view)
|
||||
{
|
||||
if (view) {
|
||||
connect(view->page(), SIGNAL(loadFinished(bool)), this, SLOT(delayedRefreshTree()));
|
||||
connect(view->page(), SIGNAL(loadStarted()), this, SLOT(delayedRefreshTree()));
|
||||
connect(view, SIGNAL(titleChanged(QString)), this, SLOT(delayedRefreshTree()));
|
||||
connect(view, SIGNAL(iconChanged()), this, SLOT(delayedRefreshTree()));
|
||||
}
|
||||
}
|
95
src/plugins/TabManager/tabmanagerwidget.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* ============================================================
|
||||
* TabManager plugin for QupZilla
|
||||
* Copyright (C) 2013 S. Razi Alavizadeh <s.r.alavizadeh@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 TABMANAGERWIDGET_H
|
||||
#define TABMANAGERWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPointer>
|
||||
#include <QHash>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class TabManagerWidget;
|
||||
}
|
||||
class QUrl;
|
||||
class QTreeWidgetItem;
|
||||
class BrowserWindow;
|
||||
class WebPage;
|
||||
class WebTab;
|
||||
class QWebView;
|
||||
class TLDExtractor;
|
||||
|
||||
class TabManagerWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum GroupType {
|
||||
GroupByWindow = 0,
|
||||
GroupByDomain = 1,
|
||||
GroupByHost = 2
|
||||
};
|
||||
|
||||
explicit TabManagerWidget(BrowserWindow* mainClass, QWidget* parent = 0, bool defaultWidget = false);
|
||||
~TabManagerWidget();
|
||||
|
||||
void closeSelectedTabs(const QHash<BrowserWindow*, WebTab*> &tabsHash);
|
||||
void detachSelectedTabs(const QHash<BrowserWindow*, WebTab*> &tabsHash);
|
||||
bool bookmarkSelectedTabs(const QHash<BrowserWindow*, WebTab*> &tabsHash);
|
||||
|
||||
void setGroupType(GroupType type);
|
||||
|
||||
static QString domainFromUrl(const QUrl &url, bool useHostName = false);
|
||||
|
||||
public slots:
|
||||
void delayedRefreshTree(WebPage* p = 0);
|
||||
void changeGroupType();
|
||||
|
||||
private:
|
||||
QTreeWidgetItem* createEmptyItem(QTreeWidgetItem* parent = 0, bool addToTree = true);
|
||||
void groupByDomainName(bool useHostName = false);
|
||||
void groupByWindow();
|
||||
BrowserWindow* getQupZilla();
|
||||
|
||||
void makeWebViewConnections(QWebView* view);
|
||||
|
||||
Ui::TabManagerWidget* ui;
|
||||
QPointer<BrowserWindow> p_QupZilla;
|
||||
WebPage* m_webPage;
|
||||
|
||||
bool m_isRefreshing;
|
||||
bool m_refreshBlocked;
|
||||
bool m_waitForRefresh;
|
||||
bool m_isDefaultWidget;
|
||||
GroupType m_groupType;
|
||||
|
||||
static TLDExtractor* s_tldExtractor;
|
||||
|
||||
private slots:
|
||||
void refreshTree();
|
||||
void processActions();
|
||||
void itemDoubleClick(QTreeWidgetItem* item, int);
|
||||
bool isTabSelected();
|
||||
void customContextMenuRequested(const QPoint &pos);
|
||||
|
||||
signals:
|
||||
void showSideBySide();
|
||||
void groupTypeChanged(TabManagerWidget::GroupType);
|
||||
};
|
||||
|
||||
#endif // TABMANAGERWIDGET_H
|
38
src/plugins/TabManager/tabmanagerwidget.ui
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabManagerWidget</class>
|
||||
<widget class="QWidget" name="TabManagerWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>266</width>
|
||||
<height>368</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tab Manager</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeWidget">
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>treeWidget</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="tabmanagerplugin.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
233
src/plugins/TabManager/tabmanagerwidgetcontroller.cpp
Normal file
@ -0,0 +1,233 @@
|
||||
/* ============================================================
|
||||
* TabManager plugin for QupZilla
|
||||
* Copyright (C) 2013 S. Razi Alavizadeh <s.r.alavizadeh@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 "tabmanagerwidgetcontroller.h"
|
||||
#include "tabmanagerwidget.h"
|
||||
#include "clickablelabel.h"
|
||||
#include "browserwindow.h"
|
||||
#include "tabwidget.h"
|
||||
#include "mainapplication.h"
|
||||
|
||||
#include <QDesktopWidget>
|
||||
#include <QStatusBar>
|
||||
#include <QAction>
|
||||
#include <QStyle>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
TabManagerWidgetController::TabManagerWidgetController(QObject* parent)
|
||||
: SideBarInterface(parent)
|
||||
, m_defaultTabManager(0)
|
||||
, m_viewType(ShowAsWindow)
|
||||
, m_groupType(TabManagerWidget::GroupByWindow)
|
||||
{
|
||||
}
|
||||
|
||||
TabManagerWidgetController::~TabManagerWidgetController()
|
||||
{
|
||||
}
|
||||
|
||||
QString TabManagerWidgetController::title() const
|
||||
{
|
||||
return tr("Tab Manager");
|
||||
}
|
||||
|
||||
QAction* TabManagerWidgetController::createMenuAction()
|
||||
{
|
||||
QAction* act = new QAction(tr("Tab Manager"), 0);
|
||||
act->setCheckable(true);
|
||||
act->setIcon(QIcon(":tabmanager/data/tabmanager.png"));
|
||||
act->setShortcut(QKeySequence("Ctrl+Shift+M"));
|
||||
act->setData("TabManager");
|
||||
|
||||
return act;
|
||||
}
|
||||
|
||||
QWidget* TabManagerWidgetController::createSideBarWidget(BrowserWindow* mainWindow)
|
||||
{
|
||||
return createTabManagerWidget(mainWindow, mainWindow);
|
||||
}
|
||||
|
||||
QWidget* TabManagerWidgetController::createStatusBarIcon(BrowserWindow* mainWindow)
|
||||
{
|
||||
if (!defaultTabManager()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_statusBarIcons.contains(mainWindow)) {
|
||||
return m_statusBarIcons.value(mainWindow);
|
||||
}
|
||||
|
||||
ClickableLabel* icon = new ClickableLabel(mainWindow);
|
||||
icon->setCursor(Qt::PointingHandCursor);
|
||||
QPixmap p(":tabmanager/data/tabmanager.png");
|
||||
icon->setPixmap(p.scaledToHeight(16));
|
||||
icon->setToolTip(tr("Show Tab Manager"));
|
||||
|
||||
QAction* showAction = createMenuAction();
|
||||
showAction->setCheckable(false);
|
||||
showAction->setParent(icon);
|
||||
mainWindow->addAction(showAction);
|
||||
connect(showAction, SIGNAL(triggered()), this, SLOT(raiseTabManager()));
|
||||
|
||||
connect(icon, SIGNAL(clicked(QPoint)), this, SLOT(raiseTabManager()));
|
||||
|
||||
m_statusBarIcons.insert(mainWindow, icon);
|
||||
m_actions.insert(mainWindow, showAction);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
TabManagerWidgetController::ViewType TabManagerWidgetController::viewType()
|
||||
{
|
||||
return m_viewType;
|
||||
}
|
||||
|
||||
void TabManagerWidgetController::setViewType(ViewType type)
|
||||
{
|
||||
m_viewType = type;
|
||||
}
|
||||
|
||||
TabManagerWidget::GroupType TabManagerWidgetController::groupType()
|
||||
{
|
||||
return m_groupType;
|
||||
}
|
||||
|
||||
void TabManagerWidgetController::setGroupType(TabManagerWidget::GroupType type)
|
||||
{
|
||||
m_groupType = type;
|
||||
}
|
||||
|
||||
TabManagerWidget* TabManagerWidgetController::createTabManagerWidget(BrowserWindow* mainClass, QWidget* parent, bool defaultWidget)
|
||||
{
|
||||
TabManagerWidget* tabManagerWidget = new TabManagerWidget(mainClass, parent, defaultWidget);
|
||||
tabManagerWidget->setGroupType(m_groupType);
|
||||
|
||||
if (defaultWidget) {
|
||||
m_defaultTabManager = tabManagerWidget;
|
||||
QAction* showAction = createMenuAction();
|
||||
showAction->setCheckable(false);
|
||||
showAction->setParent(m_defaultTabManager);
|
||||
m_defaultTabManager->addAction(showAction);
|
||||
connect(showAction, SIGNAL(triggered()), this, SLOT(raiseTabManager()));
|
||||
connect(tabManagerWidget, SIGNAL(showSideBySide()), this, SLOT(showSideBySide()));
|
||||
}
|
||||
else {
|
||||
m_defaultTabManager = 0;
|
||||
}
|
||||
|
||||
connect(tabManagerWidget, SIGNAL(groupTypeChanged(TabManagerWidget::GroupType)), this, SLOT(setGroupType(TabManagerWidget::GroupType)));
|
||||
connect(this, SIGNAL(requestRefreshTree(WebPage*)), tabManagerWidget, SLOT(delayedRefreshTree(WebPage*)));
|
||||
connect(this, SIGNAL(pinStateChanged(int,bool)), tabManagerWidget, SLOT(delayedRefreshTree()));
|
||||
|
||||
emit requestRefreshTree();
|
||||
|
||||
return tabManagerWidget;
|
||||
}
|
||||
|
||||
TabManagerWidget* TabManagerWidgetController::defaultTabManager()
|
||||
{
|
||||
return m_defaultTabManager;
|
||||
}
|
||||
|
||||
void TabManagerWidgetController::addStatusBarIcon(BrowserWindow* window)
|
||||
{
|
||||
if (window) {
|
||||
window->statusBar()->addPermanentWidget(createStatusBarIcon(window));
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerWidgetController::removeStatusBarIcon(BrowserWindow* window)
|
||||
{
|
||||
if (window) {
|
||||
window->statusBar()->removeWidget(m_statusBarIcons.value(window));
|
||||
window->removeAction(m_actions.value(window));
|
||||
delete m_actions.value(window);
|
||||
delete m_statusBarIcons.value(window);
|
||||
m_statusBarIcons.remove(window);
|
||||
m_actions.remove(window);
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerWidgetController::mainWindowCreated(BrowserWindow* window, bool refresh)
|
||||
{
|
||||
if (window) {
|
||||
addStatusBarIcon(window);
|
||||
connect(window->tabWidget(), SIGNAL(currentChanged(int)), this, SIGNAL(requestRefreshTree()));
|
||||
connect(window->tabWidget(), SIGNAL(pinStateChanged(int,bool)), this, SIGNAL(pinStateChanged(int,bool)));
|
||||
}
|
||||
|
||||
if (refresh) {
|
||||
emit requestRefreshTree();
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerWidgetController::mainWindowDeleted(BrowserWindow* window)
|
||||
{
|
||||
removeStatusBarIcon(window);
|
||||
|
||||
emit requestRefreshTree();
|
||||
}
|
||||
|
||||
void TabManagerWidgetController::raiseTabManager()
|
||||
{
|
||||
if (!defaultTabManager()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClickableLabel* icon = qobject_cast<ClickableLabel*>(sender());
|
||||
if (icon) {
|
||||
static int frameWidth = (defaultTabManager()->frameGeometry().width() - defaultTabManager()->geometry().width()) / 2;
|
||||
static int titleBarHeight = defaultTabManager()->style()->pixelMetric(QStyle::PM_TitleBarHeight);
|
||||
|
||||
int y = qMax(0, icon->mapToGlobal(QPoint(0, 0)).y() - 1 - icon->window()->height() + titleBarHeight - frameWidth);
|
||||
int x = icon->mapToGlobal(QPoint(0, 0)).x();
|
||||
if (!mApp->isRightToLeft()) {
|
||||
x -= defaultTabManager()->width();
|
||||
}
|
||||
QRect newGeo(x, y, defaultTabManager()->width(), icon->window()->height() - titleBarHeight - frameWidth);
|
||||
defaultTabManager()->setGeometry(newGeo);
|
||||
}
|
||||
|
||||
defaultTabManager()->activateWindow();
|
||||
defaultTabManager()->showNormal();
|
||||
defaultTabManager()->raise();
|
||||
}
|
||||
|
||||
void TabManagerWidgetController::showSideBySide()
|
||||
{
|
||||
if (!defaultTabManager()) {
|
||||
return;
|
||||
}
|
||||
const QRect &availableGeometry = mApp->desktop()->availableGeometry(defaultTabManager());
|
||||
static int frameWidth = (defaultTabManager()->frameGeometry().width() - defaultTabManager()->geometry().width()) / 2;
|
||||
static int titleBarHeight = defaultTabManager()->style()->pixelMetric(QStyle::PM_TitleBarHeight);
|
||||
|
||||
QRect managerRect(availableGeometry.left() + frameWidth, availableGeometry.top() + titleBarHeight,
|
||||
defaultTabManager()->width(), availableGeometry.height() - titleBarHeight - frameWidth);
|
||||
QRect qupzillaRect(managerRect.topRight().x() + 2 * frameWidth, managerRect.top(),
|
||||
availableGeometry.width() - managerRect.width() - 4 * frameWidth, managerRect.height());
|
||||
|
||||
defaultTabManager()->setGeometry(managerRect);
|
||||
mApp->getWindow()->setGeometry(qupzillaRect);
|
||||
mApp->getWindow()->showNormal();
|
||||
mApp->getWindow()->raise();
|
||||
|
||||
defaultTabManager()->show();
|
||||
defaultTabManager()->activateWindow();
|
||||
defaultTabManager()->raise();
|
||||
}
|
75
src/plugins/TabManager/tabmanagerwidgetcontroller.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* ============================================================
|
||||
* TabManager plugin for QupZilla
|
||||
* Copyright (C) 2013 S. Razi Alavizadeh <s.r.alavizadeh@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 TABMANAGERWIDGETCONTROLLER_H
|
||||
#define TABMANAGERWIDGETCONTROLLER_H
|
||||
|
||||
#include "sidebarinterface.h"
|
||||
#include "tabmanagerwidget.h"
|
||||
|
||||
class WebPage;
|
||||
|
||||
class TabManagerWidgetController : public SideBarInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ViewType {
|
||||
ShowAsSideBar = 0,
|
||||
ShowAsWindow = 1
|
||||
};
|
||||
|
||||
explicit TabManagerWidgetController(QObject* parent = 0);
|
||||
~TabManagerWidgetController();
|
||||
|
||||
QString title() const;
|
||||
QAction* createMenuAction();
|
||||
QWidget* createSideBarWidget(BrowserWindow* mainWindow);
|
||||
|
||||
QWidget* createStatusBarIcon(BrowserWindow* mainWindow);
|
||||
|
||||
ViewType viewType();
|
||||
void setViewType(ViewType type);
|
||||
|
||||
TabManagerWidget::GroupType groupType();
|
||||
TabManagerWidget* createTabManagerWidget(BrowserWindow* mainClass, QWidget* parent = 0, bool defaultWidget = false);
|
||||
|
||||
TabManagerWidget* defaultTabManager();
|
||||
|
||||
void addStatusBarIcon(BrowserWindow* window);
|
||||
void removeStatusBarIcon(BrowserWindow* window);
|
||||
|
||||
public slots:
|
||||
void setGroupType(TabManagerWidget::GroupType type);
|
||||
void mainWindowCreated(BrowserWindow* window, bool refresh = true);
|
||||
void mainWindowDeleted(BrowserWindow* window);
|
||||
void raiseTabManager();
|
||||
void showSideBySide();
|
||||
|
||||
private:
|
||||
TabManagerWidget* m_defaultTabManager;
|
||||
ViewType m_viewType;
|
||||
TabManagerWidget::GroupType m_groupType;
|
||||
|
||||
QHash<BrowserWindow*, QWidget*> m_statusBarIcons;
|
||||
QHash<BrowserWindow*, QAction*> m_actions;
|
||||
|
||||
signals:
|
||||
void requestRefreshTree(WebPage* p = 0);
|
||||
void pinStateChanged(int index, bool pinned);
|
||||
};
|
||||
|
||||
#endif // TABMANAGERWIDGETCONTROLLER_H
|
44
src/plugins/TabManager/tldextractor/COPYRIGHT
Normal file
@ -0,0 +1,44 @@
|
||||
-----------------------------------------------------------------------------
|
||||
Project: TLDExtractor and its example application
|
||||
GitHub link: https://github.com/srazi/TLDExtractor
|
||||
|
||||
CopyRight:
|
||||
/* ============================================================
|
||||
* TLDExtractor, a simple Qt interface to extract TLD part of a host
|
||||
* Copyright (C) 2014 Razi Alavizadeh <s.r.alavizadeh@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/>.
|
||||
* ============================================================ */
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
data file: data/effective_tld_names.dat
|
||||
download link: http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1
|
||||
|
||||
CopyRight:
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
test file: data/test_psl.txt
|
||||
download link: http://mxr.mozilla.org/mozilla-central/source/netwerk/test/unit/data/test_psl.txt?raw=1
|
||||
|
||||
CopyRight:
|
||||
// Copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-----------------------------------------------------------------------------
|
9079
src/plugins/TabManager/tldextractor/data/effective_tld_names.dat
Normal file
98
src/plugins/TabManager/tldextractor/data/test_psl.txt
Normal file
@ -0,0 +1,98 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
// null input.
|
||||
checkPublicSuffix(null, null);
|
||||
// Mixed case.
|
||||
checkPublicSuffix('COM', null);
|
||||
checkPublicSuffix('example.COM', 'example.com');
|
||||
checkPublicSuffix('WwW.example.COM', 'example.com');
|
||||
// Leading dot.
|
||||
checkPublicSuffix('.com', null);
|
||||
checkPublicSuffix('.example', null);
|
||||
checkPublicSuffix('.example.com', null);
|
||||
checkPublicSuffix('.example.example', null);
|
||||
// Unlisted TLD.
|
||||
checkPublicSuffix('example', null);
|
||||
checkPublicSuffix('example.example', 'example.example');
|
||||
checkPublicSuffix('b.example.example', 'example.example');
|
||||
checkPublicSuffix('a.b.example.example', 'example.example');
|
||||
// Listed, but non-Internet, TLD.
|
||||
//checkPublicSuffix('local', null);
|
||||
//checkPublicSuffix('example.local', null);
|
||||
//checkPublicSuffix('b.example.local', null);
|
||||
//checkPublicSuffix('a.b.example.local', null);
|
||||
// TLD with only 1 rule.
|
||||
checkPublicSuffix('biz', null);
|
||||
checkPublicSuffix('domain.biz', 'domain.biz');
|
||||
checkPublicSuffix('b.domain.biz', 'domain.biz');
|
||||
checkPublicSuffix('a.b.domain.biz', 'domain.biz');
|
||||
// TLD with some 2-level rules.
|
||||
checkPublicSuffix('com', null);
|
||||
checkPublicSuffix('example.com', 'example.com');
|
||||
checkPublicSuffix('b.example.com', 'example.com');
|
||||
checkPublicSuffix('a.b.example.com', 'example.com');
|
||||
checkPublicSuffix('uk.com', null);
|
||||
checkPublicSuffix('example.uk.com', 'example.uk.com');
|
||||
checkPublicSuffix('b.example.uk.com', 'example.uk.com');
|
||||
checkPublicSuffix('a.b.example.uk.com', 'example.uk.com');
|
||||
checkPublicSuffix('test.ac', 'test.ac');
|
||||
// TLD with only 1 (wildcard) rule.
|
||||
checkPublicSuffix('cy', null);
|
||||
checkPublicSuffix('c.cy', null);
|
||||
checkPublicSuffix('b.c.cy', 'b.c.cy');
|
||||
checkPublicSuffix('a.b.c.cy', 'b.c.cy');
|
||||
// More complex TLD.
|
||||
checkPublicSuffix('jp', null);
|
||||
checkPublicSuffix('test.jp', 'test.jp');
|
||||
checkPublicSuffix('www.test.jp', 'test.jp');
|
||||
checkPublicSuffix('ac.jp', null);
|
||||
checkPublicSuffix('test.ac.jp', 'test.ac.jp');
|
||||
checkPublicSuffix('www.test.ac.jp', 'test.ac.jp');
|
||||
checkPublicSuffix('kyoto.jp', null);
|
||||
checkPublicSuffix('test.kyoto.jp', 'test.kyoto.jp');
|
||||
checkPublicSuffix('ide.kyoto.jp', null);
|
||||
checkPublicSuffix('b.ide.kyoto.jp', 'b.ide.kyoto.jp');
|
||||
checkPublicSuffix('a.b.ide.kyoto.jp', 'b.ide.kyoto.jp');
|
||||
checkPublicSuffix('c.kobe.jp', null);
|
||||
checkPublicSuffix('b.c.kobe.jp', 'b.c.kobe.jp');
|
||||
checkPublicSuffix('a.b.c.kobe.jp', 'b.c.kobe.jp');
|
||||
checkPublicSuffix('city.kobe.jp', 'city.kobe.jp');
|
||||
checkPublicSuffix('www.city.kobe.jp', 'city.kobe.jp');
|
||||
// TLD with a wildcard rule and exceptions.
|
||||
checkPublicSuffix('ck', null);
|
||||
checkPublicSuffix('test.ck', null);
|
||||
checkPublicSuffix('b.test.ck', 'b.test.ck');
|
||||
checkPublicSuffix('a.b.test.ck', 'b.test.ck');
|
||||
checkPublicSuffix('www.ck', 'www.ck');
|
||||
checkPublicSuffix('www.www.ck', 'www.ck');
|
||||
// US K12.
|
||||
checkPublicSuffix('us', null);
|
||||
checkPublicSuffix('test.us', 'test.us');
|
||||
checkPublicSuffix('www.test.us', 'test.us');
|
||||
checkPublicSuffix('ak.us', null);
|
||||
checkPublicSuffix('test.ak.us', 'test.ak.us');
|
||||
checkPublicSuffix('www.test.ak.us', 'test.ak.us');
|
||||
checkPublicSuffix('k12.ak.us', null);
|
||||
checkPublicSuffix('test.k12.ak.us', 'test.k12.ak.us');
|
||||
checkPublicSuffix('www.test.k12.ak.us', 'test.k12.ak.us');
|
||||
// IDN labels.
|
||||
checkPublicSuffix('食狮.com.cn', '食狮.com.cn');
|
||||
checkPublicSuffix('食狮.公司.cn', '食狮.公司.cn');
|
||||
checkPublicSuffix('www.食狮.公司.cn', '食狮.公司.cn');
|
||||
checkPublicSuffix('shishi.公司.cn', 'shishi.公司.cn');
|
||||
checkPublicSuffix('公司.cn', null);
|
||||
checkPublicSuffix('食狮.中国', '食狮.中国');
|
||||
checkPublicSuffix('www.食狮.中国', '食狮.中国');
|
||||
checkPublicSuffix('shishi.中国', 'shishi.中国');
|
||||
checkPublicSuffix('中国', null);
|
||||
// Same as above, but punycoded.
|
||||
checkPublicSuffix('xn--85x722f.com.cn', 'xn--85x722f.com.cn');
|
||||
checkPublicSuffix('xn--85x722f.xn--55qx5d.cn', 'xn--85x722f.xn--55qx5d.cn');
|
||||
checkPublicSuffix('www.xn--85x722f.xn--55qx5d.cn', 'xn--85x722f.xn--55qx5d.cn');
|
||||
checkPublicSuffix('shishi.xn--55qx5d.cn', 'shishi.xn--55qx5d.cn');
|
||||
checkPublicSuffix('xn--55qx5d.cn', null);
|
||||
checkPublicSuffix('xn--85x722f.xn--fiqs8s', 'xn--85x722f.xn--fiqs8s');
|
||||
checkPublicSuffix('www.xn--85x722f.xn--fiqs8s', 'xn--85x722f.xn--fiqs8s');
|
||||
checkPublicSuffix('shishi.xn--fiqs8s', 'shishi.xn--fiqs8s');
|
||||
checkPublicSuffix('xn--fiqs8s', null);
|
421
src/plugins/TabManager/tldextractor/tldextractor.cpp
Normal file
@ -0,0 +1,421 @@
|
||||
/* ============================================================
|
||||
* TLDExtractor, a simple Qt interface to extract TLD part of a host
|
||||
* Copyright (C) 2014 Razi Alavizadeh <s.r.alavizadeh@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 "tldextractor.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QUrl>
|
||||
|
||||
TLDExtractor* TLDExtractor::s_instance = 0;
|
||||
|
||||
TLDExtractor::TLDExtractor(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
setDataSearchPaths();
|
||||
}
|
||||
|
||||
QStringList TLDExtractor::defaultDataSearchPaths()
|
||||
{
|
||||
return QStringList() << QLatin1String(":/tldextractor/data");
|
||||
}
|
||||
|
||||
TLDExtractor* TLDExtractor::instance()
|
||||
{
|
||||
if(s_instance == 0)
|
||||
{
|
||||
s_instance = new TLDExtractor(qApp);
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
TLDExtractor::~TLDExtractor()
|
||||
{
|
||||
s_instance = 0;
|
||||
}
|
||||
|
||||
bool TLDExtractor::isDataLoaded()
|
||||
{
|
||||
return !m_tldHash.isEmpty();
|
||||
}
|
||||
|
||||
QString TLDExtractor::TLD(const QString &host)
|
||||
{
|
||||
if (host.isEmpty() || host.startsWith(QLatin1Char('.'))) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString cleanHost = normalizedHost(host);
|
||||
|
||||
QString tldPart = cleanHost.mid(cleanHost.lastIndexOf(QLatin1Char('.')) + 1);
|
||||
cleanHost = QString::fromUtf8(QUrl::toAce(cleanHost));
|
||||
|
||||
loadData();
|
||||
|
||||
if (!m_tldHash.contains(tldPart)) {
|
||||
return tldPart;
|
||||
}
|
||||
|
||||
QStringList tldRules = m_tldHash.values(tldPart);
|
||||
|
||||
if (!tldRules.contains(tldPart)) {
|
||||
tldRules << tldPart;
|
||||
}
|
||||
|
||||
int maxLabelCount = 0;
|
||||
bool isExceptionTLD = false;
|
||||
bool isWildcardTLD = false;
|
||||
|
||||
foreach(QString rule, tldRules) {
|
||||
const int labelCount = rule.count(QLatin1Char('.')) + 1;
|
||||
|
||||
if (rule.startsWith(QLatin1Char('!'))) {
|
||||
rule = rule.remove(0, 1);
|
||||
|
||||
rule = QString::fromUtf8(QUrl::toAce(rule));
|
||||
isExceptionTLD = true;
|
||||
|
||||
// matches with exception TLD
|
||||
if (cleanHost.endsWith(rule)) {
|
||||
tldPart = rule.mid(rule.indexOf(QLatin1Char('.')) + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
isExceptionTLD = false;
|
||||
}
|
||||
|
||||
if (rule.startsWith(QLatin1Char('*'))) {
|
||||
rule.remove(0, 1);
|
||||
|
||||
if (rule.startsWith(QLatin1Char('.'))) {
|
||||
rule.remove(0, 1);
|
||||
}
|
||||
|
||||
isWildcardTLD = true;
|
||||
}
|
||||
else {
|
||||
isWildcardTLD = false;
|
||||
}
|
||||
|
||||
Q_UNUSED(isExceptionTLD)
|
||||
|
||||
rule = QString::fromUtf8(QUrl::toAce(rule));
|
||||
const QString testRule = QLatin1Char('.') + rule;
|
||||
const QString testUrl = QLatin1Char('.') + cleanHost;
|
||||
|
||||
if (labelCount > maxLabelCount && testUrl.endsWith(testRule)) {
|
||||
tldPart = rule;
|
||||
maxLabelCount = labelCount;
|
||||
|
||||
if (isWildcardTLD) {
|
||||
QString temp = cleanHost;
|
||||
temp.remove(temp.lastIndexOf(tldPart), tldPart.size());
|
||||
|
||||
if (temp.endsWith(QLatin1Char('.'))) {
|
||||
temp.remove(temp.size() - 1, 1);
|
||||
}
|
||||
|
||||
temp = temp.mid(temp.lastIndexOf(QLatin1Char('.')) + 1);
|
||||
|
||||
tldPart = temp.isEmpty() ? rule : (temp + "." + rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString temp = normalizedHost(host);
|
||||
tldPart = temp.section(QLatin1Char('.'), temp.count(QLatin1Char('.')) - tldPart.count(QLatin1Char('.')));
|
||||
|
||||
return tldPart;
|
||||
}
|
||||
|
||||
QString TLDExtractor::domain(const QString &host)
|
||||
{
|
||||
const QString tldPart = TLD(host);
|
||||
|
||||
return domainHelper(host, tldPart);
|
||||
}
|
||||
|
||||
QString TLDExtractor::domainHelper(const QString &host, const QString &tldPart)
|
||||
{
|
||||
if (host.isEmpty() || tldPart.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString temp = normalizedHost(host);
|
||||
temp.remove(temp.lastIndexOf(tldPart), tldPart.size());
|
||||
|
||||
if (temp.endsWith(QLatin1Char('.'))) {
|
||||
temp.remove(temp.size() - 1, 1);
|
||||
}
|
||||
|
||||
return temp.mid(temp.lastIndexOf(QLatin1Char('.')) + 1);
|
||||
}
|
||||
|
||||
QString TLDExtractor::registrableDomainHelper(const QString &domainPart, const QString &tldPart)
|
||||
{
|
||||
if (tldPart.isEmpty() || domainPart.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
else {
|
||||
return QString("%1.%2").arg(domainPart).arg(tldPart);
|
||||
}
|
||||
}
|
||||
|
||||
QString TLDExtractor::subdomainHelper(const QString &host, const QString ®istrablePart)
|
||||
{
|
||||
if (!registrablePart.isEmpty()) {
|
||||
QString subdomain = normalizedHost(host);
|
||||
|
||||
subdomain.remove(subdomain.lastIndexOf(registrablePart), registrablePart.size());
|
||||
|
||||
if (subdomain.endsWith(QLatin1Char('.'))) {
|
||||
subdomain.remove(subdomain.size() - 1, 1);
|
||||
}
|
||||
|
||||
return subdomain;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString TLDExtractor::registrableDomain(const QString &host)
|
||||
{
|
||||
const QString tldPart = TLD(host);
|
||||
|
||||
return registrableDomainHelper(domainHelper(host, tldPart), tldPart);
|
||||
}
|
||||
|
||||
QString TLDExtractor::subdomain(const QString &host)
|
||||
{
|
||||
return subdomainHelper(host, registrableDomain(host));
|
||||
}
|
||||
|
||||
// a light function that extract all parts with just one call to TLD()
|
||||
TLDExtractor::HostParts TLDExtractor::splitParts(const QString &host)
|
||||
{
|
||||
HostParts hostParts;
|
||||
|
||||
hostParts.host = host;
|
||||
hostParts.tld = TLD(host);
|
||||
hostParts.domain = domainHelper(host, hostParts.tld);
|
||||
hostParts.registrableDomain = registrableDomainHelper(hostParts.domain, hostParts.tld);
|
||||
hostParts.subdomain = subdomainHelper(host, hostParts.registrableDomain);
|
||||
|
||||
return hostParts;
|
||||
}
|
||||
|
||||
QStringList TLDExtractor::dataSearchPaths() const
|
||||
{
|
||||
return m_dataSearchPaths;
|
||||
}
|
||||
|
||||
void TLDExtractor::setDataSearchPaths(const QStringList &searchPaths)
|
||||
{
|
||||
m_dataSearchPaths = searchPaths;
|
||||
|
||||
m_dataSearchPaths << TLDExtractor::defaultDataSearchPaths();
|
||||
|
||||
m_dataSearchPaths.removeDuplicates();
|
||||
}
|
||||
|
||||
void TLDExtractor::loadData()
|
||||
{
|
||||
if (isDataLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString dataFileName;
|
||||
bool parsedDataFileExist = false;
|
||||
|
||||
foreach(const QString &path, m_dataSearchPaths) {
|
||||
dataFileName = QFileInfo(path + QLatin1String("/effective_tld_names.dat")).absoluteFilePath();
|
||||
|
||||
if (QFileInfo(dataFileName).exists()) {
|
||||
parsedDataFileExist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!parsedDataFileExist) {
|
||||
const QString tldDataFileDownloadLink = QLatin1String("http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1");
|
||||
QMessageBox::information(0, tr("File not found!"),
|
||||
tr("File \'effective_tld_names.dat\' was not found!\n"
|
||||
"You can download it form \'<a href=\"%1\"><b>here</b></a>\' to one of the following paths:\n%2")
|
||||
.arg(tldDataFileDownloadLink).arg(m_dataSearchPaths.join("\n")));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_dataFileName = dataFileName;
|
||||
|
||||
if (!parseData(dataFileName)) {
|
||||
qWarning() << "TLDExtractor: There is some parse errors for file:" << dataFileName;
|
||||
}
|
||||
}
|
||||
|
||||
bool TLDExtractor::parseData(const QString &dataFile, bool loadPrivateDomains)
|
||||
{
|
||||
m_tldHash.clear();
|
||||
|
||||
QFile file(dataFile);
|
||||
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool seekToEndOfPrivateDomains = false;
|
||||
|
||||
while (!file.atEnd()) {
|
||||
QString line = QString::fromUtf8(file.readLine().constData()).simplified();
|
||||
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.startsWith(QLatin1Char('.'))) {
|
||||
line.remove(0, 1);
|
||||
}
|
||||
|
||||
|
||||
if (line.startsWith(QLatin1String("//"))) {
|
||||
if (line.contains(QLatin1String("===END PRIVATE DOMAINS==="))) {
|
||||
seekToEndOfPrivateDomains = false;
|
||||
}
|
||||
|
||||
if (!loadPrivateDomains && line.contains(QLatin1String("===BEGIN PRIVATE DOMAINS==="))) {
|
||||
if (m_tldHash.isEmpty()) {
|
||||
seekToEndOfPrivateDomains = true;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (seekToEndOfPrivateDomains) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Each line is only read up to the first whitespace
|
||||
line = line.left(line.indexOf(QLatin1Char(' ')));
|
||||
|
||||
if (!line.contains(QLatin1Char('.'))) {
|
||||
m_tldHash.insertMulti(line, line);
|
||||
}
|
||||
else {
|
||||
QString key = line.mid(line.lastIndexOf(QLatin1Char('.')) + 1);
|
||||
|
||||
m_tldHash.insertMulti(key, line);
|
||||
}
|
||||
}
|
||||
|
||||
return isDataLoaded();
|
||||
}
|
||||
|
||||
QString TLDExtractor::normalizedHost(const QString &host) const
|
||||
{
|
||||
return host.toLower();
|
||||
}
|
||||
|
||||
// methods for testing
|
||||
bool TLDExtractor::test()
|
||||
{
|
||||
if (!parseData(m_dataFileName, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString testDataFileName;
|
||||
bool testDataFileExist = false;
|
||||
|
||||
foreach(const QString &path, m_dataSearchPaths) {
|
||||
testDataFileName = QFileInfo(path + QLatin1String("/test_psl.txt")).absoluteFilePath();
|
||||
|
||||
if (QFileInfo(testDataFileName).exists()) {
|
||||
testDataFileExist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!testDataFileExist) {
|
||||
const QString testFileDownloadLink = QLatin1String("http://mxr.mozilla.org/mozilla-central/source/netwerk/test/unit/data/test_psl.txt?raw=1");
|
||||
|
||||
QMessageBox::information(0, tr("File not found!"),
|
||||
tr("File \'test_psl.txt\' was not found!\n"
|
||||
"You can download it form \'<a href=\"%1\"><b>here</b></a>\' to one of the following paths:\n%2")
|
||||
.arg(testFileDownloadLink).arg(m_dataSearchPaths.join("\n")));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile file(testDataFileName);
|
||||
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QRegExp testRegExp("checkPublicSuffix\\(('([^']+)'|null), ('([^']+)'|null)\\);");
|
||||
bool allTestSuccess = true;
|
||||
|
||||
while (!file.atEnd()) {
|
||||
QString line = QString::fromUtf8(file.readLine().constData()).simplified();
|
||||
|
||||
if (line.startsWith(QLatin1String("//")) || line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
line.indexOf(testRegExp);
|
||||
|
||||
const QString hostName = testRegExp.cap(2);
|
||||
const QString registrableName = testRegExp.cap(4);
|
||||
|
||||
if (!checkPublicSuffix(hostName, registrableName)) {
|
||||
allTestSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allTestSuccess) {
|
||||
qWarning() << "TLDExtractor: Test passed successfully.";
|
||||
}
|
||||
else {
|
||||
qWarning() << "TLDExtractor: Test finished with some errors!";
|
||||
}
|
||||
|
||||
// reset cache for normal use
|
||||
m_tldHash.clear();
|
||||
|
||||
return allTestSuccess;
|
||||
}
|
||||
|
||||
bool TLDExtractor::checkPublicSuffix(const QString &hostName, const QString ®istrableName)
|
||||
{
|
||||
if (registrableDomain(hostName) != registrableName) {
|
||||
qWarning() << "TLDExtractor Test Error: hostName:" << hostName
|
||||
<< "Correct registrableName:" << registrableName
|
||||
<< "Wrong registrableName:" << registrableDomain(hostName);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
81
src/plugins/TabManager/tldextractor/tldextractor.h
Normal file
@ -0,0 +1,81 @@
|
||||
/* ============================================================
|
||||
* TLDExtractor, a simple Qt interface to extract TLD part of a host
|
||||
* Copyright (C) 2014 Razi Alavizadeh <s.r.alavizadeh@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 TLDEXTRACTOR_H
|
||||
#define TLDEXTRACTOR_H
|
||||
|
||||
#define TLDExtractor_Version "1.0"
|
||||
|
||||
#include <QHash>
|
||||
#include <QStringList>
|
||||
|
||||
class TLDExtractor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static TLDExtractor* instance();
|
||||
~TLDExtractor();
|
||||
|
||||
bool isDataLoaded();
|
||||
|
||||
struct HostParts {
|
||||
QString host;
|
||||
QString tld;
|
||||
QString domain;
|
||||
QString registrableDomain;
|
||||
QString subdomain;
|
||||
};
|
||||
|
||||
QString TLD(const QString &host);
|
||||
QString domain(const QString &host);
|
||||
QString registrableDomain(const QString &host);
|
||||
QString subdomain(const QString &host);
|
||||
|
||||
HostParts splitParts(const QString &host);
|
||||
|
||||
QStringList dataSearchPaths() const;
|
||||
void setDataSearchPaths(const QStringList &searchPaths = TLDExtractor::defaultDataSearchPaths());
|
||||
|
||||
bool test();
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(TLDExtractor)
|
||||
|
||||
static TLDExtractor* s_instance;
|
||||
TLDExtractor(QObject* parent = 0);
|
||||
|
||||
static QStringList defaultDataSearchPaths();
|
||||
|
||||
void loadData();
|
||||
bool parseData(const QString &dataFile, bool loadPrivateDomains = false);
|
||||
|
||||
QString domainHelper(const QString &host, const QString &tldPart);
|
||||
QString registrableDomainHelper(const QString &domainPart, const QString &tldPart);
|
||||
QString subdomainHelper(const QString &host, const QString ®istrablePart);
|
||||
|
||||
QString normalizedHost(const QString &host) const;
|
||||
|
||||
bool checkPublicSuffix(const QString &hostName, const QString ®istrableName);
|
||||
|
||||
QString m_dataFileName;
|
||||
QStringList m_dataSearchPaths;
|
||||
|
||||
QMultiHash<QString, QString> m_tldHash;
|
||||
};
|
||||
|
||||
#endif // TLDEXTRACTOR_H
|
14
src/plugins/TabManager/tldextractor/tldextractor.pri
Normal file
@ -0,0 +1,14 @@
|
||||
#-------------------------------------------------------------------------
|
||||
# TLDExtractor, a simple Qt interface to extract TLD part of a host
|
||||
# Copyright (C) 2014 Razi Alavizadeh <s.r.alavizadeh@gmail.com>
|
||||
#
|
||||
# Project created by QtCreator 2014-12-04T15:32:18
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
SOURCES += $$PWD/tldextractor.cpp
|
||||
HEADERS += $$PWD/tldextractor.h
|
||||
|
||||
RESOURCES += $$PWD/tldextractor.qrc
|
6
src/plugins/TabManager/tldextractor/tldextractor.qrc
Normal file
@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/tldextractor">
|
||||
<file>data/effective_tld_names.dat</file>
|
||||
<file>data/test_psl.txt</file>
|
||||
</qresource>
|
||||
</RCC>
|
110
src/plugins/TabManager/translations/de_DE.ts
Normal file
@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.0" language="de_DE">
|
||||
<context>
|
||||
<name>TabManagerPlugin</name>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="104"/>
|
||||
<source>Tab Manager View Type</source>
|
||||
<translation>Tab-Manager Darstellung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="105"/>
|
||||
<source><p>Please select view type:<br /><b>Note:</b> The "<i>Window</i>" type is recommended for managing lots of windows/tabs</source>
|
||||
<translation><p>Bitte Darstellung wählen:<br /><b>Hinweis:</b> Darstellung "<i>Fenster</i>" ist für die Verwaltung von vielen Fenstern/ Tabs empfohlen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="107"/>
|
||||
<location filename="../tabmanagerplugin.cpp" line="110"/>
|
||||
<source>SideBar</source>
|
||||
<translation>Seiten-Leiste</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="107"/>
|
||||
<source>Window</source>
|
||||
<translation>Fenster</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabManagerWidget</name>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.ui" line="14"/>
|
||||
<source>Tab Manager</source>
|
||||
<translation>Tab-Manager</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.ui" line="25"/>
|
||||
<source>Group By:</source>
|
||||
<translation>Gruppieren nach:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.ui" line="48"/>
|
||||
<source>...</source>
|
||||
<translation>...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="54"/>
|
||||
<source>Window</source>
|
||||
<translation>Fenster</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="54"/>
|
||||
<source>Domain</source>
|
||||
<translation>Domäne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="54"/>
|
||||
<source>Host</source>
|
||||
<translation>Host</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="88"/>
|
||||
<source>Local File System:</source>
|
||||
<translation>Lokales Dateisystem:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="91"/>
|
||||
<source>QupZilla:</source>
|
||||
<translation>QupZilla:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="94"/>
|
||||
<source> [FTP]</source>
|
||||
<translation> [FTP]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="412"/>
|
||||
<source>Choose folder for bookmarks:</source>
|
||||
<translation>Ordner für Lesezeichen auswählen:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="413"/>
|
||||
<source>Bookmark Selected Tabs</source>
|
||||
<translation>Ausgewählte Tabs speichern</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="526"/>
|
||||
<source>Window %1</source>
|
||||
<translation>Fenster %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="527"/>
|
||||
<source>Double click to switch</source>
|
||||
<translation>Zum Wechseln doppelklicken</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabManagerWidgetController</name>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidgetcontroller.cpp" line="46"/>
|
||||
<location filename="../tabmanagerwidgetcontroller.cpp" line="51"/>
|
||||
<source>Tab Manager</source>
|
||||
<translation>Tab-Manager</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidgetcontroller.cpp" line="79"/>
|
||||
<source>Show/Hide Tab Manager</source>
|
||||
<translation>Tab-Manager anzeigen/ verbergen</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
110
src/plugins/TabManager/translations/empty.ts
Normal file
@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.0">
|
||||
<context>
|
||||
<name>TabManagerPlugin</name>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="106"/>
|
||||
<source>Tab Manager View Type</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="107"/>
|
||||
<source><p>Please select view type:<br /><b>Note:</b> The "<i>Window</i>" type is recommended for managing lots of windows/tabs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="109"/>
|
||||
<location filename="../tabmanagerplugin.cpp" line="112"/>
|
||||
<source>SideBar</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="109"/>
|
||||
<source>Window</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabManagerWidget</name>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.ui" line="14"/>
|
||||
<source>Tab Manager</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.ui" line="25"/>
|
||||
<source>Group By:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.ui" line="48"/>
|
||||
<source>...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="54"/>
|
||||
<source>Window</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="54"/>
|
||||
<source>Domain</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="54"/>
|
||||
<source>Host</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="88"/>
|
||||
<source>Local File System:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="91"/>
|
||||
<source>QupZilla:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="94"/>
|
||||
<source> [FTP]</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="388"/>
|
||||
<source>Choose folder for bookmarks:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="389"/>
|
||||
<source>Bookmark Selected Tabs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="505"/>
|
||||
<source>Window %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="506"/>
|
||||
<source>Double click to switch</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabManagerWidgetController</name>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidgetcontroller.cpp" line="46"/>
|
||||
<location filename="../tabmanagerwidgetcontroller.cpp" line="51"/>
|
||||
<source>Tab Manager</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidgetcontroller.cpp" line="79"/>
|
||||
<source>Show Tab Manager</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
114
src/plugins/TabManager/translations/fa_IR.ts
Normal file
@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.0" language="fa_IR">
|
||||
<context>
|
||||
<name>TabManagerPlugin</name>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="106"/>
|
||||
<source>Tab Manager View Type</source>
|
||||
<translation>فرم نمایش مدیر برگه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="107"/>
|
||||
<source><p>Please select view type:<br /><b>Note:</b> The "<i>Window</i>" type is recommended for managing lots of windows/tabs</source>
|
||||
<translation><p>لطفا فرم نمایش را انتخاب کنید:<br /><b>توجه:</b> نمایش به فرم «<i>پنجره</i>» برای مدیریت تعداد زیادی پنجره و برگه توصیه میشود</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="109"/>
|
||||
<location filename="../tabmanagerplugin.cpp" line="112"/>
|
||||
<source>SideBar</source>
|
||||
<translation>نوار کناری</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerplugin.cpp" line="109"/>
|
||||
<source>Window</source>
|
||||
<translation>پنجره</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabManagerWidget</name>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.ui" line="14"/>
|
||||
<source>Tab Manager</source>
|
||||
<translation>مدیر برگه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.ui" line="25"/>
|
||||
<source>Group By:</source>
|
||||
<translation>گروهبندی با:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.ui" line="48"/>
|
||||
<source>...</source>
|
||||
<translation>...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="54"/>
|
||||
<source>Window</source>
|
||||
<translation>پنجره</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="54"/>
|
||||
<source>Domain</source>
|
||||
<translation>نام دامنه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="54"/>
|
||||
<source>Host</source>
|
||||
<translation>نام سایت</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="88"/>
|
||||
<source>Local File System:</source>
|
||||
<translation>پروندههای روی سیستم:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="91"/>
|
||||
<source>QupZilla:</source>
|
||||
<translation>کوپزیلا:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="94"/>
|
||||
<source> [FTP]</source>
|
||||
<translation> [FTP]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="388"/>
|
||||
<source>Choose folder for bookmarks:</source>
|
||||
<translation>انتخاب پوشه برای نشانها:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="389"/>
|
||||
<source>Bookmark Selected Tabs</source>
|
||||
<translation>برگههای انتخابی را نشاندار کن</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="505"/>
|
||||
<source>Window %1</source>
|
||||
<translation>پنجره %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidget.cpp" line="506"/>
|
||||
<source>Double click to switch</source>
|
||||
<translation>جفتکلیک برای نمایش پنجره</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabManagerWidgetController</name>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidgetcontroller.cpp" line="46"/>
|
||||
<location filename="../tabmanagerwidgetcontroller.cpp" line="51"/>
|
||||
<source>Tab Manager</source>
|
||||
<translation>مدیر برگه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../tabmanagerwidgetcontroller.cpp" line="79"/>
|
||||
<source>Show Tab Manager</source>
|
||||
<translation>نمایش مدیر برگه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show/Hide Tab Manager</source>
|
||||
<translation type="obsolete">نمایش/مخفیسازی مدیر برگه</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|