diff --git a/autotests/autotests.h b/autotests/autotests.h index ca4d21a3..1b3ac1ff 100644 --- a/autotests/autotests.h +++ b/autotests/autotests.h @@ -1,48 +1,48 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 David Rosca * * 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 . * ============================================================ */ #include "mainapplication.h" #include "qztools.h" #include #define FALKONTEST_MAIN(Test) \ int main(int argc, char **argv) \ { \ - QzTools::removeDir(QDir::tempPath() + QSL("/Falkon-test")); \ + QzTools::removeRecursively(QDir::tempPath() + QSL("/Falkon-test")); \ MainApplication::setTestModeEnabled(true); \ MainApplication app(argc, argv); \ QTEST_DISABLE_KEYPAD_NAVIGATION; \ Test test; \ return QTest::qExec(&test, argc, argv); \ } bool waitForLoadfinished(QObject *object) { if (qstrcmp(object->metaObject()->className(), "WebTab") == 0) { QSignalSpy spy(object, SIGNAL(loadingChanged(bool))); while (spy.wait()) { if (spy.count() > 0 && spy.at(0).at(0).toBool()) { return true; } spy.clear(); } return false; } qDebug() << "Unsupported object" << object; return false; } diff --git a/autotests/qztoolstest.cpp b/autotests/qztoolstest.cpp index 3a433b38..5d705f6c 100644 --- a/autotests/qztoolstest.cpp +++ b/autotests/qztoolstest.cpp @@ -1,279 +1,383 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2013-2014 David Rosca * * 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 . * ============================================================ */ #include "qztoolstest.h" #include "qztools.h" #include #include void QzToolsTest::initTestCase() { m_tmpPath = QDir::tempPath() + QL1S("/falkon-test/qztoolstest"); QDir().mkpath(m_tmpPath); QVERIFY(QDir(m_tmpPath).exists()); } void QzToolsTest::cleanupTestCase() { QDir().rmpath(m_tmpPath); QVERIFY(!QDir(m_tmpPath).exists()); } void QzToolsTest::samePartOfStrings_data() { QTest::addColumn("string1"); QTest::addColumn("string2"); QTest::addColumn("result"); // Lorem ipsum dolor sit amet, consectetur adipiscing elit. QTest::newRow("General") << "Lorem ipsum dolor" << "Lorem ipsum dolor Test_1" << "Lorem ipsum dolor"; QTest::newRow("OneChar") << "L" << "LTest_1" << "L"; QTest::newRow("EmptyReturn") << "Lorem ipsum dolor" << "orem ipsum dolor Test_1" << ""; QTest::newRow("EmptyString1") << "" << "orem ipsum dolor Test_1" << ""; QTest::newRow("EmptyString2") << "Lorem ipsum dolor" << "" << ""; QTest::newRow("EmptyBoth") << "" << "" << ""; } void QzToolsTest::samePartOfStrings() { QFETCH(QString, string1); QFETCH(QString, string2); QFETCH(QString, result); QCOMPARE(QzTools::samePartOfStrings(string1, string2), result); } void QzToolsTest::getFileNameFromUrl_data() { QTest::addColumn("url"); QTest::addColumn("result"); QTest::newRow("Basic") << QUrl("http://www.google.com/filename.html") << "filename.html"; QTest::newRow("OnlyHost") << QUrl("http://www.google.com/") << "www.google.com"; QTest::newRow("OnlyHostWithoutSlash") << QUrl("http://www.google.com") << "www.google.com"; QTest::newRow("EndingDirectory") << QUrl("http://www.google.com/filename/") << "filename"; QTest::newRow("EmptyUrl") << QUrl("") << ""; QTest::newRow("OnlyScheme") << QUrl("http:") << ""; QTest::newRow("FileSchemeUrl") << QUrl("file:///usr/share/test/file.tx") << "file.tx"; QTest::newRow("FileSchemeUrlDirectory") << QUrl("file:///usr/share/test/") << "test"; QTest::newRow("FileSchemeUrlRoot") << QUrl("file:///") << ""; } void QzToolsTest::getFileNameFromUrl() { QFETCH(QUrl, url); QFETCH(QString, result); QCOMPARE(QzTools::getFileNameFromUrl(url), result); } void QzToolsTest::splitCommandArguments_data() { QTest::addColumn("command"); QTest::addColumn("result"); QTest::newRow("Basic") << "/usr/bin/foo -o foo.out" << (QStringList() << "/usr/bin/foo" << "-o" << "foo.out"); QTest::newRow("Empty") << QString() << QStringList(); QTest::newRow("OnlySpaces") << QString(" ") << QStringList(); QTest::newRow("OnlyQuotes") << QString("\"\" \"\"") << QStringList(); QTest::newRow("EmptyQuotesAndSpace") << QString("\"\" \"\" \" \"") << QStringList(" "); QTest::newRow("MultipleSpaces") << " /usr/foo -o foo.out " << (QStringList() << "/usr/foo" << "-o" << "foo.out"); QTest::newRow("Quotes") << "\"/usr/foo\" \"-o\" \"foo.out\"" << (QStringList() << "/usr/foo" << "-o" << "foo.out"); QTest::newRow("SingleQuotes") << "'/usr/foo' '-o' 'foo.out'" << (QStringList() << "/usr/foo" << "-o" << "foo.out"); QTest::newRow("SingleAndDoubleQuotes") << " '/usr/foo' \"-o\" 'foo.out' " << (QStringList() << "/usr/foo" << "-o" << "foo.out"); QTest::newRow("SingleInDoubleQuotes") << "/usr/foo \"-o 'ds' \" 'foo.out' " << (QStringList() << "/usr/foo" << "-o 'ds' " << "foo.out"); QTest::newRow("DoubleInSingleQuotes") << "/usr/foo -o 'foo\" d \".out' " << (QStringList() << "/usr/foo" << "-o" << "foo\" d \".out"); QTest::newRow("SpacesWithQuotes") << QString(" \" \" \" \" ") << (QStringList() << " " << " "); QTest::newRow("QuotesAndSpaces") << "/usr/foo -o \"foo - out\"" << (QStringList() << "/usr/foo" << "-o" << "foo - out"); QTest::newRow("EqualAndQuotes") << "/usr/foo -o=\"foo - out\"" << (QStringList() << "/usr/foo" << "-o=foo - out"); QTest::newRow("EqualWithSpaces") << "/usr/foo -o = \"foo - out\"" << (QStringList() << "/usr/foo" << "-o" << "=" << "foo - out"); QTest::newRow("MultipleSpacesAndQuotes") << " /usr/foo -o=\" foo.out \" " << (QStringList() << "/usr/foo" << "-o= foo.out "); // Unmatched quotes should be treated as an error QTest::newRow("UnmatchedQuote") << "/usr/bin/foo -o \"bar" << QStringList(); } void QzToolsTest::splitCommandArguments() { QFETCH(QString, command); QFETCH(QStringList, result); QCOMPARE(QzTools::splitCommandArguments(command), result); } void QzToolsTest::escapeSqlGlobString_data() { QTest::addColumn("input"); QTest::addColumn("result"); QTest::newRow("NothingToEscape") << "http://test" << "http://test"; QTest::newRow("Escape *") << "http://test*/heh" << "http://test[*]/heh"; QTest::newRow("Escape **") << "http://test**/he*h" << "http://test[*][*]/he[*]h"; QTest::newRow("Escape ?") << "http://test?/heh" << "http://test[?]/heh"; QTest::newRow("Escape ??") << "http://t??est?/heh" << "http://t[?][?]est[?]/heh"; QTest::newRow("Escape [") << "http://[test/heh" << "http://[[]test/heh"; QTest::newRow("Escape [[") << "http://[[te[st/heh" << "http://[[][[]te[[]st/heh"; QTest::newRow("Escape ]") << "http://]test/heh" << "http://[]]test/heh"; QTest::newRow("Escape ]]") << "http://]]te]st/heh" << "http://[]][]]te[]]st/heh"; QTest::newRow("Escape []") << "http://[]test/heh" << "http://[[][]]test/heh"; QTest::newRow("Escape [][[]][]") << "http://t[][[]][]est/heh" << "http://t[[][]][[][[][]][]][[][]]est/heh"; QTest::newRow("Escape [?]][[*]") << "http://t[?]][[*]est/heh" << "http://t[[][?][]][]][[][[][*][]]est/heh"; } void QzToolsTest::escapeSqlGlobString() { QFETCH(QString, input); QFETCH(QString, result); QCOMPARE(QzTools::escapeSqlGlobString(input), result); } class TempFile { QString name; public: explicit TempFile(const QString &name) : name(name) { QFile file(name); file.open(QFile::WriteOnly); file.write(QByteArrayLiteral("falkon-test")); file.close(); } ~TempFile() { QFile::remove(name); } }; void QzToolsTest::ensureUniqueFilename() { QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out")), createPath("test.out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test")), createPath("test")); // default appendFormat = (%1) { TempFile f1(createPath("test.out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out")), createPath("test(1).out")); TempFile f2(createPath("test(1).out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out")), createPath("test(2).out")); TempFile f3(createPath("test(2).out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out")), createPath("test(3).out")); } { TempFile f1(createPath("test")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test")), createPath("test(1)")); TempFile f2(createPath("test(1)")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test")), createPath("test(2)")); TempFile f3(createPath("test(2)")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test")), createPath("test(3)")); } { TempFile f1(createPath("test(1)")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test")), createPath("test")); TempFile f2(createPath("test")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test")), createPath("test(2)")); } // appendFormat = %1 { QString appendFormat = QSL("%1"); TempFile f1(createPath("test.out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out"), appendFormat), createPath("test1.out")); TempFile f2(createPath("test1.out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out"), appendFormat), createPath("test2.out")); TempFile f3(createPath("test2.out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out"), appendFormat), createPath("test3.out")); } { QString appendFormat = QSL("%1"); TempFile f1(createPath("test")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test1")); TempFile f2(createPath("test1")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test2")); TempFile f3(createPath("test2")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test3")); } { QString appendFormat = QSL("%1"); TempFile f1(createPath("test1")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test")); TempFile f2(createPath("test")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test2")); } // appendFormat = .%1 { QString appendFormat = QSL(".%1"); TempFile f1(createPath("test.out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out"), appendFormat), createPath("test.1.out")); TempFile f2(createPath("test.1.out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out"), appendFormat), createPath("test.2.out")); TempFile f3(createPath("test.2.out")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test.out"), appendFormat), createPath("test.3.out")); } { QString appendFormat = QSL(".%1"); TempFile f1(createPath("test")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test.1")); TempFile f2(createPath("test.1")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test.2")); TempFile f3(createPath("test.2")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test.3")); } { QString appendFormat = QSL(".%1"); TempFile f1(createPath("test.1")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test")); TempFile f2(createPath("test")); QCOMPARE(QzTools::ensureUniqueFilename(createPath("test"), appendFormat), createPath("test.2")); } } +static void createTestDirectoryStructure(const QString &path) +{ + QDir().mkdir(path); + QDir dir(path); + dir.mkdir("dir1"); + dir.mkdir("dir2"); + dir.mkdir("dir3"); + dir.cd("dir1"); + dir.mkdir("dir1_1"); + dir.mkdir("dir1_2"); + dir.mkdir("dir1_3"); + dir.cdUp(); + dir.cd("dir3"); + dir.mkdir("dir3_1"); + QFile file(path + "/dir1/dir1_2/file1.txt"); + file.open(QFile::WriteOnly); + file.write("test"); + file.close(); +} + +void QzToolsTest::copyRecursivelyTest() +{ + const QString testDir = createPath("copyRecursivelyTest"); + createTestDirectoryStructure(testDir); + + QVERIFY(!QFileInfo(testDir + "-copy").exists()); + + // Copy to non-existant target + QCOMPARE(QzTools::copyRecursively(testDir, testDir + "-copy"), true); + + QCOMPARE(QFileInfo(testDir + "-copy").isDir(), true); + QCOMPARE(QFileInfo(testDir + "-copy/dir1").isDir(), true); + QCOMPARE(QFileInfo(testDir + "-copy/dir2").isDir(), true); + QCOMPARE(QFileInfo(testDir + "-copy/dir3").isDir(), true); + QCOMPARE(QFileInfo(testDir + "-copy/dir1/dir1_1").isDir(), true); + QCOMPARE(QFileInfo(testDir + "-copy/dir1/dir1_2").isDir(), true); + QCOMPARE(QFileInfo(testDir + "-copy/dir1/dir1_3").isDir(), true); + QCOMPARE(QFileInfo(testDir + "-copy/dir3/dir3_1").isDir(), true); + QCOMPARE(QFileInfo(testDir + "-copy/dir1/dir1_2/file1.txt").isFile(), true); + + QFile file(testDir + "-copy/dir1/dir1_2/file1.txt"); + file.open(QFile::ReadOnly); + QCOMPARE(file.readAll(), QByteArray("test")); + + // Copy to target that already exists + QCOMPARE(QzTools::copyRecursively(testDir, testDir + "-copy"), false); + + // Cleanup + QCOMPARE(QzTools::removeRecursively(testDir), true); + QCOMPARE(QzTools::removeRecursively(testDir + "-copy"), true); +} + +void QzToolsTest::removeRecursivelyTest() +{ + const QString testDir = createPath("removeRecursivelyTest"); + createTestDirectoryStructure(testDir); + + QCOMPARE(QzTools::copyRecursively(testDir, testDir + "-copy"), true); + QCOMPARE(QzTools::removeRecursively(testDir + "-copy"), true); + QCOMPARE(QFileInfo(testDir + "-copy").exists(), false); + + // Remove non-existant path returns success + QCOMPARE(QzTools::removeRecursively(testDir + "-copy"), true); + + QCOMPARE(QzTools::copyRecursively(testDir, testDir + "-copy2"), true); + + QFile dir(testDir + "-copy2"); + dir.setPermissions(dir.permissions() & ~(QFile::WriteOwner | QFile::WriteUser | QFile::WriteGroup | QFile::WriteOther)); + + QCOMPARE(QzTools::removeRecursively(testDir + "-copy2"), false); + + dir.setPermissions(dir.permissions() | QFile::WriteOwner); + + QCOMPARE(QzTools::removeRecursively(testDir + "-copy2"), true); + + // Cleanup + QCOMPARE(QzTools::removeRecursively(testDir), true); +} + +void QzToolsTest::dontFollowSymlinksTest() +{ + const QString testDir = createPath("removeRecursivelyTest"); + createTestDirectoryStructure(testDir); + + QDir().mkpath(testDir + "/subdir"); + QFile::link(testDir, testDir + "/subdir/link"); + + QVERIFY(QzTools::removeRecursively(testDir + "/subdir")); + + QVERIFY(!QFile::exists(testDir + "/subdir")); + QVERIFY(QFile::exists(testDir)); + + QDir().mkpath(testDir + "/subdir/normalfolder"); + QFile::link("..", testDir + "/subdir/link"); + + QVERIFY(QzTools::copyRecursively(testDir + "/subdir", testDir + "/subdir2")); + + QCOMPARE(QFile::exists(testDir + "/subdir2/link"), true); + QCOMPARE(QFile::exists(testDir + "/subdir2/normalfolder"), true); + + // Cleanup + QCOMPARE(QzTools::removeRecursively(testDir), true); +} + QString QzToolsTest::createPath(const char *file) const { return m_tmpPath + QL1S("/") + file; } QTEST_GUILESS_MAIN(QzToolsTest) diff --git a/autotests/qztoolstest.h b/autotests/qztoolstest.h index 479123f1..92ecd76c 100644 --- a/autotests/qztoolstest.h +++ b/autotests/qztoolstest.h @@ -1,52 +1,55 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2013-2014 David Rosca * * 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 . * ============================================================ */ #ifndef QZTOOLSTEST_H #define QZTOOLSTEST_H #include class QzToolsTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void samePartOfStrings_data(); void samePartOfStrings(); void getFileNameFromUrl_data(); void getFileNameFromUrl(); void splitCommandArguments_data(); void splitCommandArguments(); void escapeSqlGlobString_data(); void escapeSqlGlobString(); void ensureUniqueFilename(); + void copyRecursivelyTest(); + void removeRecursivelyTest(); + void dontFollowSymlinksTest(); private: QString createPath(const char *file) const; QString m_tmpPath; }; #endif // QZTOOLSTEST_H diff --git a/src/lib/app/mainapplication.cpp b/src/lib/app/mainapplication.cpp index 7ef2081d..29094c56 100644 --- a/src/lib/app/mainapplication.cpp +++ b/src/lib/app/mainapplication.cpp @@ -1,1213 +1,1213 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * 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 . * ============================================================ */ #include "mainapplication.h" #include "history.h" #include "qztools.h" #include "updater.h" #include "autofill.h" #include "settings.h" #include "autosaver.h" #include "datapaths.h" #include "tabwidget.h" #include "cookiejar.h" #include "bookmarks.h" #include "qzsettings.h" #include "proxystyle.h" #include "pluginproxy.h" #include "iconprovider.h" #include "browserwindow.h" #include "checkboxdialog.h" #include "networkmanager.h" #include "profilemanager.h" #include "restoremanager.h" #include "browsinglibrary.h" #include "downloadmanager.h" #include "clearprivatedata.h" #include "useragentmanager.h" #include "commandlineoptions.h" #include "searchenginesmanager.h" #include "desktopnotificationsfactory.h" #include "html5permissions/html5permissionsmanager.h" #include "scripts.h" #include "sessionmanager.h" #include "closedwindowsmanager.h" #include "../config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #include #endif #include #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) #include "registerqappassociation.h" #endif static bool s_testMode = false; MainApplication::MainApplication(int &argc, char** argv) : QtSingleApplication(argc, argv) , m_isPrivate(false) , m_isPortable(false) , m_isClosing(false) , m_isStartingAfterCrash(false) , m_history(0) , m_bookmarks(0) , m_autoFill(0) , m_cookieJar(0) , m_plugins(0) , m_browsingLibrary(0) , m_networkManager(0) , m_restoreManager(0) , m_sessionManager(0) , m_downloadManager(0) , m_userAgentManager(0) , m_searchEnginesManager(0) , m_closedWindowsManager(0) , m_html5PermissionsManager(0) , m_desktopNotifications(0) , m_webProfile(0) , m_autoSaver(0) #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) , m_registerQAppAssociation(0) #endif { setAttribute(Qt::AA_UseHighDpiPixmaps); setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); setApplicationName(QLatin1String("falkon")); setOrganizationDomain(QLatin1String("org.kde")); setWindowIcon(QIcon::fromTheme(QSL("falkon"), QIcon(QSL(":icons/falkon.svg")))); setDesktopFileName(QSL("org.kde.falkon")); #ifdef GIT_REVISION setApplicationVersion(QSL("%1 (%2)").arg(Qz::VERSION, GIT_REVISION)); #else setApplicationVersion(Qz::VERSION); #endif // Set fallback icon theme (eg. on Windows/Mac) if (QIcon::fromTheme(QSL("view-refresh")).isNull()) { QIcon::setThemeName(QSL("breeze-fallback")); } // QSQLITE database plugin is required if (!QSqlDatabase::isDriverAvailable(QSL("QSQLITE"))) { QMessageBox::critical(0, QSL("Error"), QSL("Qt SQLite database plugin is not available. Please install it and restart the application.")); m_isClosing = true; return; } #ifdef Q_OS_WIN // Set default app font (needed for N'ko) int fontId = QFontDatabase::addApplicationFont(QSL("font.ttf")); if (fontId != -1) { const QStringList families = QFontDatabase::applicationFontFamilies(fontId); if (!families.empty()) setFont(QFont(families.at(0))); } #endif QUrl startUrl; QString startProfile; QStringList messages; bool noAddons = false; bool newInstance = false; if (argc > 1) { CommandLineOptions cmd; foreach (const CommandLineOptions::ActionPair &pair, cmd.getActions()) { switch (pair.action) { case Qz::CL_StartWithoutAddons: noAddons = true; break; case Qz::CL_StartWithProfile: startProfile = pair.text; break; case Qz::CL_StartPortable: m_isPortable = true; break; case Qz::CL_NewTab: messages.append(QLatin1String("ACTION:NewTab")); m_postLaunchActions.append(OpenNewTab); break; case Qz::CL_NewWindow: messages.append(QLatin1String("ACTION:NewWindow")); break; case Qz::CL_ToggleFullScreen: messages.append(QLatin1String("ACTION:ToggleFullScreen")); m_postLaunchActions.append(ToggleFullScreen); break; case Qz::CL_ShowDownloadManager: messages.append(QLatin1String("ACTION:ShowDownloadManager")); m_postLaunchActions.append(OpenDownloadManager); break; case Qz::CL_StartPrivateBrowsing: m_isPrivate = true; break; case Qz::CL_StartNewInstance: newInstance = true; break; case Qz::CL_OpenUrlInCurrentTab: startUrl = QUrl::fromUserInput(pair.text); messages.append("ACTION:OpenUrlInCurrentTab" + pair.text); break; case Qz::CL_OpenUrlInNewWindow: startUrl = QUrl::fromUserInput(pair.text); messages.append("ACTION:OpenUrlInNewWindow" + pair.text); break; case Qz::CL_OpenUrl: startUrl = QUrl::fromUserInput(pair.text); messages.append("URL:" + pair.text); break; case Qz::CL_ExitAction: m_isClosing = true; return; default: break; } } } if (!isPortable()) { QSettings falkonConf(QSL("%1/falkon.conf").arg(applicationDirPath()), QSettings::IniFormat); m_isPortable = falkonConf.value(QSL("Config/Portable")).toBool(); } if (isPortable()) { std::cout << "Falkon: Running in Portable Mode." << std::endl; DataPaths::setPortableVersion(); } // Don't start single application in private browsing if (!isPrivate()) { QString appId = QLatin1String("FalkonWebBrowser"); if (isPortable()) { appId.append(QLatin1String("Portable")); } if (isTestModeEnabled()) { appId.append(QSL("TestMode")); } if (newInstance) { if (startProfile.isEmpty() || startProfile == QLatin1String("default")) { std::cout << "New instance cannot be started with default profile!" << std::endl; } else { // Generate unique appId so it is possible to start more separate instances // of the same profile. It is dangerous to run more instances of the same profile, // but if the user wants it, we should allow it. appId.append(startProfile + QString::number(QDateTime::currentMSecsSinceEpoch())); } } setAppId(appId); } // If there is nothing to tell other instance, we need to at least wake it if (messages.isEmpty()) { messages.append(QLatin1String(" ")); } if (isRunning()) { m_isClosing = true; foreach (const QString &message, messages) { sendMessage(message); } return; } #ifdef Q_OS_MACOS setQuitOnLastWindowClosed(false); // disable tabbing issue#2261 extern void disableWindowTabbing(); disableWindowTabbing(); #else setQuitOnLastWindowClosed(true); #endif QSettings::setDefaultFormat(QSettings::IniFormat); QDesktopServices::setUrlHandler(QSL("http"), this, "addNewTab"); QDesktopServices::setUrlHandler(QSL("https"), this, "addNewTab"); QDesktopServices::setUrlHandler(QSL("ftp"), this, "addNewTab"); ProfileManager profileManager; profileManager.initConfigDir(); profileManager.initCurrentProfile(startProfile); Settings::createSettings(DataPaths::currentProfilePath() + QLatin1String("/settings.ini")); m_webProfile = isPrivate() ? new QWebEngineProfile(this) : QWebEngineProfile::defaultProfile(); connect(m_webProfile, &QWebEngineProfile::downloadRequested, this, &MainApplication::downloadRequested); m_networkManager = new NetworkManager(this); setupUserScripts(); if (!isPrivate() && !isTestModeEnabled()) { m_sessionManager = new SessionManager(this); m_autoSaver = new AutoSaver(this); connect(m_autoSaver, SIGNAL(save()), m_sessionManager, SLOT(autoSaveLastSession())); Settings settings; settings.beginGroup(QSL("SessionRestore")); const bool wasRunning = settings.value(QSL("isRunning"), false).toBool(); const bool wasRestoring = settings.value(QSL("isRestoring"), false).toBool(); settings.setValue(QSL("isRunning"), true); settings.setValue(QSL("isRestoring"), wasRunning); settings.endGroup(); settings.sync(); m_isStartingAfterCrash = wasRunning && wasRestoring; if (wasRunning) { QTimer::singleShot(60 * 1000, this, [this]() { Settings().setValue(QSL("SessionRestore/isRestoring"), false); }); } // we have to ask about startup session before creating main window if (!m_isStartingAfterCrash && afterLaunch() == SelectSession) m_restoreManager = new RestoreManager(sessionManager()->askSessionFromUser()); } loadSettings(); m_plugins = new PluginProxy(this); m_autoFill = new AutoFill(this); if (!noAddons) m_plugins->loadPlugins(); BrowserWindow* window = createWindow(Qz::BW_FirstAppWindow, startUrl); connect(window, SIGNAL(startingCompleted()), this, SLOT(restoreOverrideCursor())); connect(this, SIGNAL(focusChanged(QWidget*,QWidget*)), this, SLOT(onFocusChanged())); if (!isPrivate() && !isTestModeEnabled()) { #ifndef DISABLE_CHECK_UPDATES Settings settings; bool checkUpdates = settings.value("Web-Browser-Settings/CheckUpdates", true).toBool(); if (checkUpdates) { new Updater(window); } #endif sessionManager()->backupSavedSessions(); if (m_isStartingAfterCrash || afterLaunch() == RestoreSession) { m_restoreManager = new RestoreManager(sessionManager()->lastActiveSessionPath()); if (!m_restoreManager->isValid()) { destroyRestoreManager(); } } if (!m_isStartingAfterCrash && m_restoreManager) { restoreSession(window, m_restoreManager->restoreData()); } } QTimer::singleShot(0, this, SLOT(postLaunch())); } MainApplication::~MainApplication() { IconProvider::instance()->saveIconsToDatabase(); // Wait for all QtConcurrent jobs to finish QThreadPool::globalInstance()->waitForDone(); // Delete all classes that are saving data in destructor delete m_bookmarks; m_bookmarks = nullptr; delete m_cookieJar; m_cookieJar = nullptr; Settings::syncSettings(); } bool MainApplication::isClosing() const { return m_isClosing; } bool MainApplication::isPrivate() const { return m_isPrivate; } bool MainApplication::isPortable() const { #ifdef PORTABLE_BUILD return true; #else return m_isPortable; #endif } bool MainApplication::isStartingAfterCrash() const { return m_isStartingAfterCrash; } int MainApplication::windowCount() const { return m_windows.count(); } QList MainApplication::windows() const { return m_windows; } BrowserWindow* MainApplication::getWindow() const { if (m_lastActiveWindow) { return m_lastActiveWindow.data(); } return m_windows.isEmpty() ? 0 : m_windows.at(0); } BrowserWindow* MainApplication::createWindow(Qz::BrowserWindowType type, const QUrl &startUrl) { if (windowCount() == 0 && type != Qz::BW_MacFirstWindow) { type = Qz::BW_FirstAppWindow; } BrowserWindow* window = new BrowserWindow(type, startUrl); connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(windowDestroyed(QObject*))); m_windows.prepend(window); return window; } MainApplication::AfterLaunch MainApplication::afterLaunch() const { return static_cast(Settings().value(QSL("Web-URL-Settings/afterLaunch"), RestoreSession).toInt()); } void MainApplication::openSession(BrowserWindow* window, RestoreData &restoreData) { setOverrideCursor(Qt::BusyCursor); if (!window) window = createWindow(Qz::BW_OtherRestoredWindow); if (window->tabCount() != 0) { // This can only happen when recovering crashed session! // Don't restore tabs in current window as user already opened some new tabs. createWindow(Qz::BW_OtherRestoredWindow)->restoreWindow(restoreData.windows.takeAt(0)); } else { window->restoreWindow(restoreData.windows.takeAt(0)); } foreach (const BrowserWindow::SavedWindow &data, restoreData.windows) { BrowserWindow* window = createWindow(Qz::BW_OtherRestoredWindow); window->restoreWindow(data); } m_closedWindowsManager->restoreState(restoreData.closedWindows); restoreOverrideCursor(); } bool MainApplication::restoreSession(BrowserWindow* window, RestoreData restoreData) { if (m_isPrivate || !restoreData.isValid()) { return false; } openSession(window, restoreData); m_restoreManager->clearRestoreData(); destroyRestoreManager(); return true; } void MainApplication::destroyRestoreManager() { if (m_restoreManager && m_restoreManager->isValid()) { return; } delete m_restoreManager; m_restoreManager = 0; } void MainApplication::reloadSettings() { loadSettings(); emit settingsReloaded(); } QString MainApplication::styleName() const { return m_proxyStyle ? m_proxyStyle->name() : QString(); } void MainApplication::setProxyStyle(ProxyStyle *style) { m_proxyStyle = style; setStyle(style); } History* MainApplication::history() { if (!m_history) { m_history = new History(this); } return m_history; } Bookmarks* MainApplication::bookmarks() { if (!m_bookmarks) { m_bookmarks = new Bookmarks(this); } return m_bookmarks; } AutoFill* MainApplication::autoFill() { return m_autoFill; } CookieJar* MainApplication::cookieJar() { if (!m_cookieJar) { m_cookieJar = new CookieJar(this); } return m_cookieJar; } PluginProxy* MainApplication::plugins() { return m_plugins; } BrowsingLibrary* MainApplication::browsingLibrary() { if (!m_browsingLibrary) { m_browsingLibrary = new BrowsingLibrary(getWindow()); } return m_browsingLibrary; } NetworkManager *MainApplication::networkManager() { return m_networkManager; } RestoreManager* MainApplication::restoreManager() { return m_restoreManager; } SessionManager* MainApplication::sessionManager() { return m_sessionManager; } DownloadManager* MainApplication::downloadManager() { if (!m_downloadManager) { m_downloadManager = new DownloadManager(); } return m_downloadManager; } UserAgentManager* MainApplication::userAgentManager() { if (!m_userAgentManager) { m_userAgentManager = new UserAgentManager(this); } return m_userAgentManager; } SearchEnginesManager* MainApplication::searchEnginesManager() { if (!m_searchEnginesManager) { m_searchEnginesManager = new SearchEnginesManager(this); } return m_searchEnginesManager; } ClosedWindowsManager* MainApplication::closedWindowsManager() { if (!m_closedWindowsManager) { m_closedWindowsManager = new ClosedWindowsManager(this); } return m_closedWindowsManager; } HTML5PermissionsManager* MainApplication::html5PermissionsManager() { if (!m_html5PermissionsManager) { m_html5PermissionsManager = new HTML5PermissionsManager(this); } return m_html5PermissionsManager; } DesktopNotificationsFactory* MainApplication::desktopNotifications() { if (!m_desktopNotifications) { m_desktopNotifications = new DesktopNotificationsFactory(this); } return m_desktopNotifications; } QWebEngineProfile *MainApplication::webProfile() const { return m_webProfile; } QWebEngineSettings *MainApplication::webSettings() const { return m_webProfile->settings(); } // static MainApplication* MainApplication::instance() { return static_cast(QCoreApplication::instance()); } // static bool MainApplication::isTestModeEnabled() { return s_testMode; } // static void MainApplication::setTestModeEnabled(bool enabled) { s_testMode = enabled; } void MainApplication::addNewTab(const QUrl &url) { BrowserWindow* window = getWindow(); if (window) { window->tabWidget()->addView(url, url.isEmpty() ? Qz::NT_SelectedNewEmptyTab : Qz::NT_SelectedTabAtTheEnd); } } void MainApplication::startPrivateBrowsing(const QUrl &startUrl) { QUrl url = startUrl; if (QAction* act = qobject_cast(sender())) { url = act->data().toUrl(); } QStringList args; args.append(QSL("--private-browsing")); args.append(QSL("--profile=") + ProfileManager::currentProfile()); if (!url.isEmpty()) { args << url.toEncoded(); } if (!QProcess::startDetached(applicationFilePath(), args)) { qWarning() << "MainApplication: Cannot start new browser process for private browsing!" << applicationFilePath() << args; } } void MainApplication::reloadUserStyleSheet() { const QString userCssFile = Settings().value("Web-Browser-Settings/userStyleSheet", QString()).toString(); setUserStyleSheet(userCssFile); } void MainApplication::restoreOverrideCursor() { QApplication::restoreOverrideCursor(); } void MainApplication::changeOccurred() { if (m_autoSaver) m_autoSaver->changeOccurred(); } void MainApplication::quitApplication() { if (m_downloadManager && !m_downloadManager->canClose()) { m_downloadManager->show(); return; } for (BrowserWindow *window : qAsConst(m_windows)) { emit window->aboutToClose(); } if (m_sessionManager && m_windows.count() > 0) { m_sessionManager->autoSaveLastSession(); } m_isClosing = true; for (BrowserWindow *window : qAsConst(m_windows)) { window->close(); } // Saving settings in saveSettings() slot called from quit() so // everything gets saved also when quitting application in other // way than clicking Quit action in File menu or closing last window // eg. on Mac (#157) if (!isPrivate()) { removeLockFile(); } quit(); } void MainApplication::postLaunch() { if (m_postLaunchActions.contains(OpenDownloadManager)) { downloadManager()->show(); } if (m_postLaunchActions.contains(OpenNewTab)) { getWindow()->tabWidget()->addView(QUrl(), Qz::NT_SelectedNewEmptyTab); } if (m_postLaunchActions.contains(ToggleFullScreen)) { getWindow()->toggleFullScreen(); } QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, DataPaths::currentProfilePath()); connect(this, SIGNAL(messageReceived(QString)), this, SLOT(messageReceived(QString))); connect(this, SIGNAL(aboutToQuit()), this, SLOT(saveSettings())); createJumpList(); initPulseSupport(); QTimer::singleShot(5000, this, &MainApplication::runDeferredPostLaunchActions); } QByteArray MainApplication::saveState() const { RestoreData restoreData; restoreData.windows.reserve(m_windows.count()); for (BrowserWindow *window : qAsConst(m_windows)) { restoreData.windows.append(BrowserWindow::SavedWindow(window)); } if (m_restoreManager && m_restoreManager->isValid()) { QDataStream stream(&restoreData.crashedSession, QIODevice::WriteOnly); stream << m_restoreManager->restoreData(); } restoreData.closedWindows = m_closedWindowsManager->saveState(); QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << Qz::sessionVersion; stream << restoreData; return data; } void MainApplication::saveSettings() { if (isPrivate()) { return; } m_isClosing = true; Settings settings; settings.beginGroup("SessionRestore"); settings.setValue("isRunning", false); settings.setValue("isRestoring", false); settings.endGroup(); settings.beginGroup("Web-Browser-Settings"); bool deleteCache = settings.value("deleteCacheOnClose", false).toBool(); bool deleteHistory = settings.value("deleteHistoryOnClose", false).toBool(); bool deleteHtml5Storage = settings.value("deleteHTML5StorageOnClose", false).toBool(); settings.endGroup(); settings.beginGroup("Cookie-Settings"); bool deleteCookies = settings.value("deleteCookiesOnClose", false).toBool(); settings.endGroup(); if (deleteHistory) { m_history->clearHistory(); } if (deleteHtml5Storage) { ClearPrivateData::clearLocalStorage(); } if (deleteCookies) { m_cookieJar->deleteAllCookies(); } if (deleteCache) { - QzTools::removeDir(mApp->webProfile()->cachePath()); + QzTools::removeRecursively(mApp->webProfile()->cachePath()); } m_searchEnginesManager->saveSettings(); m_plugins->shutdown(); m_networkManager->shutdown(); qzSettings->saveSettings(); QFile::remove(DataPaths::currentProfilePath() + QLatin1String("/WebpageIcons.db")); sessionManager()->saveSettings(); } void MainApplication::messageReceived(const QString &message) { QWidget* actWin = getWindow(); QUrl actUrl; if (message.startsWith(QLatin1String("URL:"))) { const QUrl url = QUrl::fromUserInput(message.mid(4)); addNewTab(url); actWin = getWindow(); } else if (message.startsWith(QLatin1String("ACTION:"))) { const QString text = message.mid(7); if (text == QLatin1String("NewTab")) { addNewTab(); } else if (text == QLatin1String("NewWindow")) { actWin = createWindow(Qz::BW_NewWindow); } else if (text == QLatin1String("ShowDownloadManager")) { downloadManager()->show(); actWin = downloadManager(); } else if (text == QLatin1String("ToggleFullScreen") && actWin) { BrowserWindow* qz = static_cast(actWin); qz->toggleFullScreen(); } else if (text.startsWith(QLatin1String("OpenUrlInCurrentTab"))) { actUrl = QUrl::fromUserInput(text.mid(19)); } else if (text.startsWith(QLatin1String("OpenUrlInNewWindow"))) { createWindow(Qz::BW_NewWindow, QUrl::fromUserInput(text.mid(18))); return; } } else { // User attempted to start another instance, let's open a new window actWin = createWindow(Qz::BW_NewWindow); } if (!actWin) { if (!isClosing()) { // It can only occur if download manager window was still opened createWindow(Qz::BW_NewWindow, actUrl); } return; } actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); actWin->raise(); actWin->activateWindow(); actWin->setFocus(); BrowserWindow* win = qobject_cast(actWin); if (win && !actUrl.isEmpty()) { win->loadAddress(actUrl); } } void MainApplication::windowDestroyed(QObject* window) { // qobject_cast doesn't work because QObject::destroyed is emitted from destructor Q_ASSERT(static_cast(window)); Q_ASSERT(m_windows.contains(static_cast(window))); m_windows.removeOne(static_cast(window)); } void MainApplication::onFocusChanged() { BrowserWindow* activeBrowserWindow = qobject_cast(activeWindow()); if (activeBrowserWindow) { m_lastActiveWindow = activeBrowserWindow; emit activeWindowChanged(m_lastActiveWindow); } } void MainApplication::runDeferredPostLaunchActions() { checkDefaultWebBrowser(); checkOptimizeDatabase(); } void MainApplication::downloadRequested(QWebEngineDownloadItem *download) { downloadManager()->download(download); } void MainApplication::loadSettings() { Settings settings; settings.beginGroup("Themes"); QString activeTheme = settings.value("activeTheme", DEFAULT_THEME_NAME).toString(); settings.endGroup(); loadTheme(activeTheme); QWebEngineSettings* webSettings = m_webProfile->settings(); // Web browsing settings settings.beginGroup("Web-Browser-Settings"); webSettings->setAttribute(QWebEngineSettings::LocalStorageEnabled, settings.value("HTML5StorageEnabled", true).toBool()); webSettings->setAttribute(QWebEngineSettings::PluginsEnabled, settings.value("allowPlugins", true).toBool()); webSettings->setAttribute(QWebEngineSettings::JavascriptEnabled, settings.value("allowJavaScript", true).toBool()); webSettings->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, settings.value("allowJavaScriptOpenWindow", false).toBool()); webSettings->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, settings.value("allowJavaScriptAccessClipboard", true).toBool()); webSettings->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, settings.value("IncludeLinkInFocusChain", false).toBool()); webSettings->setAttribute(QWebEngineSettings::XSSAuditingEnabled, settings.value("XSSAuditing", false).toBool()); webSettings->setAttribute(QWebEngineSettings::PrintElementBackgrounds, settings.value("PrintElementBackground", true).toBool()); webSettings->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, settings.value("SpatialNavigation", false).toBool()); webSettings->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, settings.value("AnimateScrolling", true).toBool()); webSettings->setAttribute(QWebEngineSettings::HyperlinkAuditingEnabled, false); webSettings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); webSettings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); webSettings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); webSettings->setDefaultTextEncoding(settings.value("DefaultEncoding", webSettings->defaultTextEncoding()).toString()); setWheelScrollLines(settings.value("wheelScrollLines", wheelScrollLines()).toInt()); const QString userCss = settings.value("userStyleSheet", QString()).toString(); settings.endGroup(); setUserStyleSheet(userCss); settings.beginGroup("Browser-Fonts"); webSettings->setFontFamily(QWebEngineSettings::StandardFont, settings.value("StandardFont", webSettings->fontFamily(QWebEngineSettings::StandardFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::CursiveFont, settings.value("CursiveFont", webSettings->fontFamily(QWebEngineSettings::CursiveFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::FantasyFont, settings.value("FantasyFont", webSettings->fontFamily(QWebEngineSettings::FantasyFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::FixedFont, settings.value("FixedFont", webSettings->fontFamily(QWebEngineSettings::FixedFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::SansSerifFont, settings.value("SansSerifFont", webSettings->fontFamily(QWebEngineSettings::SansSerifFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::SerifFont, settings.value("SerifFont", webSettings->fontFamily(QWebEngineSettings::SerifFont)).toString()); webSettings->setFontSize(QWebEngineSettings::DefaultFontSize, settings.value("DefaultFontSize", 15).toInt()); webSettings->setFontSize(QWebEngineSettings::DefaultFixedFontSize, settings.value("FixedFontSize", 14).toInt()); webSettings->setFontSize(QWebEngineSettings::MinimumFontSize, settings.value("MinimumFontSize", 3).toInt()); webSettings->setFontSize(QWebEngineSettings::MinimumLogicalFontSize, settings.value("MinimumLogicalFontSize", 5).toInt()); settings.endGroup(); QWebEngineProfile* profile = QWebEngineProfile::defaultProfile(); profile->setPersistentCookiesPolicy(QWebEngineProfile::AllowPersistentCookies); profile->setPersistentStoragePath(DataPaths::currentProfilePath()); QString defaultPath = DataPaths::path(DataPaths::Cache); if (!defaultPath.startsWith(DataPaths::currentProfilePath())) defaultPath.append(QLatin1Char('/') + ProfileManager::currentProfile()); const QString &cachePath = settings.value("Web-Browser-Settings/CachePath", defaultPath).toString(); profile->setCachePath(cachePath); const bool allowCache = settings.value(QSL("Web-Browser-Settings/AllowLocalCache"), true).toBool(); profile->setHttpCacheType(allowCache ? QWebEngineProfile::DiskHttpCache : QWebEngineProfile::MemoryHttpCache); const int cacheSize = settings.value(QSL("Web-Browser-Settings/LocalCacheSize"), 50).toInt() * 1000 * 1000; profile->setHttpCacheMaximumSize(cacheSize); settings.beginGroup(QSL("SpellCheck")); profile->setSpellCheckEnabled(settings.value(QSL("Enabled"), false).toBool()); profile->setSpellCheckLanguages(settings.value(QSL("Languages")).toStringList()); settings.endGroup(); if (isPrivate()) { webSettings->setAttribute(QWebEngineSettings::LocalStorageEnabled, false); history()->setSaving(false); } if (m_downloadManager) { m_downloadManager->loadSettings(); } qzSettings->loadSettings(); userAgentManager()->loadSettings(); networkManager()->loadSettings(); } void MainApplication::loadTheme(const QString &name) { QString activeThemePath = DataPaths::locate(DataPaths::Themes, name); if (activeThemePath.isEmpty()) { qWarning() << "Cannot load theme " << name; activeThemePath = QString("%1/%2").arg(DataPaths::path(DataPaths::Themes), DEFAULT_THEME_NAME); } QString qss = QzTools::readAllFileContents(activeThemePath + QLatin1String("/main.css")); #if defined(Q_OS_MACOS) qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/mac.css"))); #elif defined(Q_OS_UNIX) qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/linux.css"))); #elif defined(Q_OS_WIN) || defined(Q_OS_OS2) qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/windows.css"))); #endif if (isRightToLeft()) { qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/rtl.css"))); } if (isPrivate()) { qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/private.css"))); } qss.append(QzTools::readAllFileContents(DataPaths::currentProfilePath() + QL1S("/userChrome.css"))); QString relativePath = QDir::current().relativeFilePath(activeThemePath); qss.replace(QRegularExpression(QSL("url\\s*\\(\\s*([^\\*:\\);]+)\\s*\\)")), QString("url(%1/\\1)").arg(relativePath)); setStyleSheet(qss); } void MainApplication::checkDefaultWebBrowser() { if (isPortable()) { return; } #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) Settings settings; bool checkNow = settings.value("Web-Browser-Settings/CheckDefaultBrowser", DEFAULT_CHECK_DEFAULTBROWSER).toBool(); if (!checkNow) { return; } bool checkAgain = true; if (!associationManager()->isDefaultForAllCapabilities()) { CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, getWindow()); dialog.setDefaultButton(QMessageBox::Yes); dialog.setText(tr("Falkon is not currently your default browser. Would you like to make it your default browser?")); dialog.setCheckBoxText(tr("Always perform this check when starting Falkon.")); dialog.setDefaultCheckState(Qt::Checked); dialog.setWindowTitle(tr("Default Browser")); dialog.setIcon(QMessageBox::Warning); if (dialog.exec() == QMessageBox::Yes) { if (!mApp->associationManager()->showNativeDefaultAppSettingsUi()) mApp->associationManager()->registerAllAssociation(); } checkAgain = dialog.isChecked(); } settings.setValue("Web-Browser-Settings/CheckDefaultBrowser", checkAgain); #endif } void MainApplication::checkOptimizeDatabase() { Settings settings; settings.beginGroup(QSL("Browser")); const int numberOfRuns = settings.value(QSL("RunsWithoutOptimizeDb"), 0).toInt(); settings.setValue(QSL("RunsWithoutOptimizeDb"), numberOfRuns + 1); if (numberOfRuns > 20) { std::cout << "Optimizing database..." << std::endl; IconProvider::instance()->clearOldIconsInDatabase(); settings.setValue(QSL("RunsWithoutOptimizeDb"), 0); } settings.endGroup(); } void MainApplication::setupUserScripts() { // WebChannel for SafeJsWorld QWebEngineScript script; script.setName(QSL("_falkon_webchannel")); script.setInjectionPoint(QWebEngineScript::DocumentCreation); script.setWorldId(WebPage::SafeJsWorld); script.setRunsOnSubFrames(true); script.setSourceCode(Scripts::setupWebChannel(script.worldId())); m_webProfile->scripts()->insert(script); // WebChannel for UnsafeJsWorld QWebEngineScript script2; script2.setName(QSL("_falkon_webchannel2")); script2.setInjectionPoint(QWebEngineScript::DocumentCreation); script2.setWorldId(WebPage::UnsafeJsWorld); script2.setRunsOnSubFrames(true); script2.setSourceCode(Scripts::setupWebChannel(script2.worldId())); m_webProfile->scripts()->insert(script2); // document.window object addons QWebEngineScript script3; script3.setName(QSL("_falkon_window_object")); script3.setInjectionPoint(QWebEngineScript::DocumentCreation); script3.setWorldId(WebPage::UnsafeJsWorld); script3.setRunsOnSubFrames(true); script3.setSourceCode(Scripts::setupWindowObject()); m_webProfile->scripts()->insert(script3); } void MainApplication::setUserStyleSheet(const QString &filePath) { QString userCss; #if !defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) // Don't grey out selection on losing focus (to prevent graying out found text) QString highlightColor; QString highlightedTextColor; #ifdef Q_OS_MACOS highlightColor = QLatin1String("#b6d6fc"); highlightedTextColor = QLatin1String("#000"); #else QPalette pal = style()->standardPalette(); highlightColor = pal.color(QPalette::Highlight).name(); highlightedTextColor = pal.color(QPalette::HighlightedText).name(); #endif userCss += QString("::selection {background: %1; color: %2;} ").arg(highlightColor, highlightedTextColor); #endif userCss += QzTools::readAllFileContents(filePath).remove(QLatin1Char('\n')); const QString name = QStringLiteral("_falkon_userstylesheet"); QWebEngineScript oldScript = m_webProfile->scripts()->findScript(name); if (!oldScript.isNull()) { m_webProfile->scripts()->remove(oldScript); } if (userCss.isEmpty()) return; QWebEngineScript script; script.setName(name); script.setInjectionPoint(QWebEngineScript::DocumentReady); script.setWorldId(WebPage::SafeJsWorld); script.setRunsOnSubFrames(true); script.setSourceCode(Scripts::setCss(userCss)); m_webProfile->scripts()->insert(script); } void MainApplication::createJumpList() { #ifdef Q_OS_WIN QWinJumpList *jumpList = new QWinJumpList(this); jumpList->clear(); // Frequent QWinJumpListCategory *frequent = jumpList->frequent(); frequent->setVisible(true); const QVector mostList = m_history->mostVisited(7); for (const HistoryEntry &entry : mostList) { frequent->addLink(IconProvider::iconForUrl(entry.url), entry.title, applicationFilePath(), QStringList{entry.url.toEncoded()}); } // Tasks QWinJumpListCategory *tasks = jumpList->tasks(); tasks->setVisible(true); tasks->addLink(IconProvider::newTabIcon(), tr("Open new tab"), applicationFilePath(), {QSL("--new-tab")}); tasks->addLink(IconProvider::newWindowIcon(), tr("Open new window"), applicationFilePath(), {QSL("--new-window")}); tasks->addLink(IconProvider::privateBrowsingIcon(), tr("Open new private window"), applicationFilePath(), {QSL("--private-browsing")}); #endif } void MainApplication::initPulseSupport() { qputenv("PULSE_PROP_OVERRIDE_application.name", "Falkon"); qputenv("PULSE_PROP_OVERRIDE_application.icon_name", "falkon"); qputenv("PULSE_PROP_OVERRIDE_media.icon_name", "falkon"); } #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) RegisterQAppAssociation* MainApplication::associationManager() { if (!m_registerQAppAssociation) { QString desc = tr("Falkon is a new and very fast Qt web browser. Falkon is licensed under GPL version 3 or (at your option) any later version. It is based on QtWebEngine and Qt Framework."); QString fileIconPath = QApplication::applicationFilePath() + ",1"; QString appIconPath = QApplication::applicationFilePath() + ",0"; m_registerQAppAssociation = new RegisterQAppAssociation("Falkon", QApplication::applicationFilePath(), appIconPath, desc, this); m_registerQAppAssociation->addCapability(".html", "FalkonHTML", "Falkon HTML Document", fileIconPath, RegisterQAppAssociation::FileAssociation); m_registerQAppAssociation->addCapability(".htm", "FalkonHTML", "Falkon HTML Document", fileIconPath, RegisterQAppAssociation::FileAssociation); m_registerQAppAssociation->addCapability("http", "FalkonURL", "Falkon URL", appIconPath, RegisterQAppAssociation::UrlAssociation); m_registerQAppAssociation->addCapability("https", "FalkonURL", "Falkon URL", appIconPath, RegisterQAppAssociation::UrlAssociation); m_registerQAppAssociation->addCapability("ftp", "FalkonURL", "Falkon URL", appIconPath, RegisterQAppAssociation::UrlAssociation); } return m_registerQAppAssociation; } #endif #ifdef Q_OS_MACOS #include bool MainApplication::event(QEvent* e) { switch (e->type()) { case QEvent::FileOpen: { QFileOpenEvent *ev = static_cast(e); if (!ev->url().isEmpty()) { addNewTab(ev->url()); } else if (!ev->file().isEmpty()) { addNewTab(QUrl::fromLocalFile(ev->file())); } else { return false; } return true; } case QEvent::ApplicationActivate: if (!activeWindow() && m_windows.isEmpty()) createWindow(Qz::BW_NewWindow); break; default: break; } return QtSingleApplication::event(e); } #endif diff --git a/src/lib/app/profilemanager.cpp b/src/lib/app/profilemanager.cpp index d0499e66..11b1f95c 100644 --- a/src/lib/app/profilemanager.cpp +++ b/src/lib/app/profilemanager.cpp @@ -1,277 +1,277 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * 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 . * ============================================================ */ #include "profilemanager.h" #include "mainapplication.h" #include "datapaths.h" #include "updater.h" #include "qztools.h" #include "sqldatabase.h" #include #include #include #include #include #include #include ProfileManager::ProfileManager() { } void ProfileManager::initConfigDir() { QDir dir(DataPaths::path(DataPaths::Config)); if (dir.exists() && QFile(dir.filePath(QLatin1String("profiles/profiles.ini"))).exists()) { return; } std::cout << "Falkon: Creating new profile directory" << std::endl; if (!dir.exists()) { dir.mkpath(dir.absolutePath()); } dir.mkdir(QLatin1String("profiles")); dir.cd(QLatin1String("profiles")); // $Config/profiles QFile(dir.filePath(QLatin1String("profiles.ini"))).remove(); QFile(QLatin1String(":data/profiles.ini")).copy(dir.filePath(QLatin1String("profiles.ini"))); QFile(dir.filePath(QLatin1String("profiles.ini"))).setPermissions(QFile::ReadUser | QFile::WriteUser); dir.mkdir(QLatin1String("default")); dir.cd(QLatin1String("default")); // $Config/profiles/default QFile(QLatin1String(":data/bookmarks.json")).copy(dir.filePath(QLatin1String("bookmarks.json"))); QFile(dir.filePath(QLatin1String("bookmarks.json"))).setPermissions(QFile::ReadUser | QFile::WriteUser); QFile versionFile(dir.filePath(QLatin1String("version"))); versionFile.open(QFile::WriteOnly); versionFile.write(Qz::VERSION); versionFile.close(); } void ProfileManager::initCurrentProfile(const QString &profileName) { QString profilePath = DataPaths::path(DataPaths::Profiles) + QLatin1Char('/'); if (profileName.isEmpty()) { profilePath.append(startingProfile()); } else { profilePath.append(profileName); } DataPaths::setCurrentProfilePath(profilePath); updateCurrentProfile(); connectDatabase(); } int ProfileManager::createProfile(const QString &profileName) { QDir dir(DataPaths::path(DataPaths::Profiles)); if (QDir(dir.absolutePath() + QLatin1Char('/') + profileName).exists()) { return -1; } if (!dir.mkdir(profileName)) { return -2; } dir.cd(profileName); QFile versionFile(dir.filePath(QLatin1String("version"))); versionFile.open(QFile::WriteOnly); versionFile.write(Qz::VERSION); versionFile.close(); return 0; } bool ProfileManager::removeProfile(const QString &profileName) { QDir dir(DataPaths::path(DataPaths::Profiles) + QLatin1Char('/') + profileName); if (!dir.exists()) { return false; } - QzTools::removeDir(dir.absolutePath()); + QzTools::removeRecursively(dir.absolutePath()); return true; } // static QString ProfileManager::currentProfile() { QString path = DataPaths::currentProfilePath(); return path.mid(path.lastIndexOf(QLatin1Char('/')) + 1); } // static QString ProfileManager::startingProfile() { QSettings settings(DataPaths::path(DataPaths::Profiles) + QLatin1String("/profiles.ini"), QSettings::IniFormat); return settings.value(QLatin1String("Profiles/startProfile"), QLatin1String("default")).toString(); } // static void ProfileManager::setStartingProfile(const QString &profileName) { QSettings settings(DataPaths::path(DataPaths::Profiles) + QLatin1String("/profiles.ini"), QSettings::IniFormat); settings.setValue(QLatin1String("Profiles/startProfile"), profileName); } // static QStringList ProfileManager::availableProfiles() { QDir dir(DataPaths::path(DataPaths::Profiles)); return dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); } void ProfileManager::updateCurrentProfile() { QDir profileDir(DataPaths::currentProfilePath()); if (!profileDir.exists()) { QDir newDir(profileDir.path().remove(profileDir.dirName())); newDir.mkdir(profileDir.dirName()); } QFile versionFile(profileDir.filePath(QLatin1String("version"))); // If file exists, just update the profile to current version if (versionFile.exists()) { versionFile.open(QFile::ReadOnly); QString profileVersion = versionFile.readAll(); versionFile.close(); updateProfile(Qz::VERSION, profileVersion.trimmed()); } else { copyDataToProfile(); } versionFile.open(QFile::WriteOnly); versionFile.write(Qz::VERSION); versionFile.close(); } void ProfileManager::updateProfile(const QString ¤t, const QString &profile) { if (current == profile) { return; } Updater::Version prof(profile); // Profile is from newer version than running application if (prof > Updater::Version(Qz::VERSION)) { // Only copy data when profile is not from development version if (prof.revisionNumber != 99) { copyDataToProfile(); } return; } if (prof < Updater::Version("1.9.0")) { std::cout << "Falkon: Using profile from QupZilla " << qPrintable(profile) << " is not supported!" << std::endl; return; } // No change in 2.0 if (prof < Updater::Version("2.9.99")) { return; } // Nothing for now } void ProfileManager::copyDataToProfile() { QDir profileDir(DataPaths::currentProfilePath()); QFile browseData(profileDir.filePath(QLatin1String("browsedata.db"))); if (browseData.exists()) { const QString browseDataBackup = QzTools::ensureUniqueFilename(profileDir.filePath(QLatin1String("browsedata-backup.db"))); browseData.copy(browseDataBackup); browseData.remove(); QFile settings(profileDir.filePath(QSL("settings.ini"))); if (settings.exists()) { const QString settingsBackup = QzTools::ensureUniqueFilename(profileDir.filePath(QSL("settings-backup.ini"))); settings.copy(settingsBackup); settings.remove(); } QFile sessionFile(profileDir.filePath(QSL("session.dat"))); if (sessionFile.exists()) { QString oldVersion = QzTools::readAllFileContents(profileDir.filePath(QSL("version"))).trimmed(); if (oldVersion.isEmpty()) { oldVersion = QSL("unknown-version"); } const QString sessionBackup = QzTools::ensureUniqueFilename(profileDir.filePath(QSL("sessions/backup-%1.dat").arg(oldVersion))); sessionFile.copy(sessionBackup); sessionFile.remove(); } const QString text = "Incompatible profile version has been detected. To avoid losing your profile data, they were " "backed up in following file:

" + browseDataBackup + "
"; QMessageBox::warning(0, "Falkon: Incompatible profile version", text); } } void ProfileManager::connectDatabase() { QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE")); if (!db.isValid()) { qCritical() << "Qt sqlite database driver is missing! Continuing without database...."; return; } if (mApp->isPrivate()) { db.setConnectOptions("QSQLITE_OPEN_READONLY"); } db.setDatabaseName(DataPaths::currentProfilePath() + QLatin1String("/browsedata.db")); if (!db.open()) { qCritical() << "Cannot open SQLite database! Continuing without database...."; return; } if (db.tables().isEmpty()) { const QStringList statements = QzTools::readAllFileContents(QSL(":/data/browsedata.sql")).split(QL1C(';')); for (const QString &statement : statements) { const QString stmt = statement.trimmed(); if (stmt.isEmpty()) { continue; } QSqlQuery query; if (!query.exec(stmt)) { qCritical() << "Error creating database schema" << query.lastError().text(); } } } SqlDatabase::instance()->setDatabase(db); } diff --git a/src/lib/other/clearprivatedata.cpp b/src/lib/other/clearprivatedata.cpp index ce84be5b..3df5020d 100644 --- a/src/lib/other/clearprivatedata.cpp +++ b/src/lib/other/clearprivatedata.cpp @@ -1,243 +1,243 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * 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 . * ============================================================ */ #include "clearprivatedata.h" #include "browserwindow.h" #include "tabwidget.h" #include "cookiejar.h" #include "history.h" #include "settings.h" #include "datapaths.h" #include "mainapplication.h" #include "networkmanager.h" #include "ui_clearprivatedata.h" #include "iconprovider.h" #include "qztools.h" #include "cookiemanager.h" #include "desktopnotificationsfactory.h" #include #include #include #include #include #include #include #include ClearPrivateData::ClearPrivateData(QWidget* parent) : QDialog(parent) , ui(new Ui::ClearPrivateData) { setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); ui->buttonBox->setFocus(); connect(ui->history, SIGNAL(clicked(bool)), this, SLOT(historyClicked(bool))); connect(ui->clear, SIGNAL(clicked(bool)), this, SLOT(dialogAccepted())); connect(ui->optimizeDb, SIGNAL(clicked(bool)), this, SLOT(optimizeDb())); connect(ui->editCookies, SIGNAL(clicked()), this, SLOT(showCookieManager())); Settings settings; settings.beginGroup("ClearPrivateData"); restoreState(settings.value("state", QByteArray()).toByteArray()); settings.endGroup(); } void ClearPrivateData::historyClicked(bool state) { ui->historyLength->setEnabled(state); } void ClearPrivateData::clearLocalStorage() { const QString profile = DataPaths::currentProfilePath(); - QzTools::removeDir(profile + "/Local Storage"); + QzTools::removeRecursively(profile + "/Local Storage"); } void ClearPrivateData::clearWebDatabases() { const QString profile = DataPaths::currentProfilePath(); - QzTools::removeDir(profile + "/IndexedDB"); - QzTools::removeDir(profile + "/databases"); + QzTools::removeRecursively(profile + "/IndexedDB"); + QzTools::removeRecursively(profile + "/databases"); } void ClearPrivateData::clearCache() { const QString profile = DataPaths::currentProfilePath(); - QzTools::removeDir(profile + "/GPUCache"); + QzTools::removeRecursively(profile + "/GPUCache"); mApp->webProfile()->clearHttpCache(); } void ClearPrivateData::closeEvent(QCloseEvent* e) { Settings settings; settings.beginGroup("ClearPrivateData"); settings.setValue("state", saveState()); settings.endGroup(); e->accept(); } void ClearPrivateData::dialogAccepted() { QApplication::setOverrideCursor(Qt::WaitCursor); if (ui->history->isChecked()) { qint64 start = QDateTime::currentMSecsSinceEpoch(); qint64 end = 0; const QDate today = QDate::currentDate(); const QDate week = today.addDays(1 - today.dayOfWeek()); const QDate month = QDate(today.year(), today.month(), 1); switch (ui->historyLength->currentIndex()) { case 0: //Later Today end = QDateTime(today).toMSecsSinceEpoch(); break; case 1: //Week end = QDateTime(week).toMSecsSinceEpoch(); break; case 2: //Month end = QDateTime(month).toMSecsSinceEpoch(); break; case 3: //All break; } if (end == 0) { mApp->history()->clearHistory(); } else { const QList &indexes = mApp->history()->indexesFromTimeRange(start, end); mApp->history()->deleteHistoryEntry(indexes); } } if (ui->cookies->isChecked()) { mApp->cookieJar()->deleteAllCookies(); } if (ui->cache->isChecked()) { clearCache(); } if (ui->databases->isChecked()) { clearWebDatabases(); } if (ui->localStorage->isChecked()) { clearLocalStorage(); } QApplication::restoreOverrideCursor(); ui->clear->setEnabled(false); ui->clear->setText(tr("Done")); QTimer::singleShot(1000, this, SLOT(close())); } void ClearPrivateData::optimizeDb() { mApp->setOverrideCursor(Qt::WaitCursor); const QString profilePath = DataPaths::currentProfilePath(); QString sizeBefore = QzTools::fileSizeToString(QFileInfo(profilePath + "/browsedata.db").size()); IconProvider::instance()->clearOldIconsInDatabase(); QString sizeAfter = QzTools::fileSizeToString(QFileInfo(profilePath + "/browsedata.db").size()); mApp->restoreOverrideCursor(); QMessageBox::information(this, tr("Database Optimized"), tr("Database successfully optimized.

Database Size Before: %1
Database Size After: %2").arg(sizeBefore, sizeAfter)); } void ClearPrivateData::showCookieManager() { CookieManager* dialog = new CookieManager(this); dialog->show(); } static const int stateDataVersion = 0x0001; void ClearPrivateData::restoreState(const QByteArray &state) { QDataStream stream(state); if (stream.atEnd()) { return; } int version = -1; int historyIndex = -1; bool databases = false; bool localStorage = false; bool cache = false; bool cookies = false; bool icons = false; stream >> version; if (version != stateDataVersion) { return; } stream >> historyIndex; stream >> databases; stream >> localStorage; stream >> cache; stream >> cookies; stream >> icons; if (historyIndex != -1) { ui->history->setChecked(true); ui->historyLength->setEnabled(true); ui->historyLength->setCurrentIndex(historyIndex); } ui->databases->setChecked(databases); ui->localStorage->setChecked(localStorage); ui->cache->setChecked(cache); ui->cookies->setChecked(cookies); } QByteArray ClearPrivateData::saveState() { // history - web database - local storage - cache - cookies - icons QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << stateDataVersion; if (!ui->history->isChecked()) { stream << -1; } else { stream << ui->historyLength->currentIndex(); } stream << ui->databases->isChecked(); stream << ui->localStorage->isChecked(); stream << ui->cache->isChecked(); stream << ui->cookies->isChecked(); return data; } diff --git a/src/lib/tools/qztools.cpp b/src/lib/tools/qztools.cpp index f1884ad8..b71242ba 100644 --- a/src/lib/tools/qztools.cpp +++ b/src/lib/tools/qztools.cpp @@ -1,969 +1,1003 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * 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 . * ============================================================ */ #include "qztools.h" #include "datapaths.h" #include "settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef QZ_WS_X11 #include #include #endif #ifdef Q_OS_WIN #include +#else +#include #endif #ifdef Q_OS_MACOS #include #endif QByteArray QzTools::pixmapToByteArray(const QPixmap &pix) { QByteArray bytes; QBuffer buffer(&bytes); buffer.open(QIODevice::WriteOnly); if (pix.save(&buffer, "PNG")) { return buffer.buffer().toBase64(); } return QByteArray(); } QPixmap QzTools::pixmapFromByteArray(const QByteArray &data) { QPixmap image; QByteArray bArray = QByteArray::fromBase64(data); image.loadFromData(bArray); return image; } QUrl QzTools::pixmapToDataUrl(const QPixmap &pix) { const QString data(pixmapToByteArray(pix)); return data.isEmpty() ? QUrl() : QUrl(QSL("data:image/png;base64,") + data); } QPixmap QzTools::dpiAwarePixmap(const QString &path) { const QIcon icon(path); if (icon.availableSizes().isEmpty()) { return QPixmap(path); } return icon.pixmap(icon.availableSizes().at(0)); } QString QzTools::readAllFileContents(const QString &filename) { return QString::fromUtf8(readAllFileByteContents(filename)); } QByteArray QzTools::readAllFileByteContents(const QString &filename) { QFile file(filename); if (!filename.isEmpty() && file.open(QFile::ReadOnly)) { const QByteArray a = file.readAll(); file.close(); return a; } return QByteArray(); } void QzTools::centerWidgetOnScreen(QWidget* w) { const QRect screen = QApplication::desktop()->screenGeometry(w); const QRect size = w->geometry(); w->move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2); } // Very, very, very simplified QDialog::adjustPosition from qdialog.cpp void QzTools::centerWidgetToParent(QWidget* w, QWidget* parent) { if (!parent || !w) { return; } QPoint p; parent = parent->window(); QPoint pp = parent->mapToGlobal(QPoint(0, 0)); p = QPoint(pp.x() + parent->width() / 2, pp.y() + parent->height() / 2); p = QPoint(p.x() - w->width() / 2, p.y() - w->height() / 2 - 20); w->move(p); } -bool QzTools::removeFile(const QString &fullFileName) +bool QzTools::removeRecursively(const QString &filePath) { - QFile f(fullFileName); - if (f.exists()) { - return f.remove(); + const QFileInfo fileInfo(filePath); + if (!fileInfo.exists() && !fileInfo.isSymLink()) { + return true; } - else { + if (fileInfo.isDir() && !fileInfo.isSymLink()) { + QDir dir(filePath); + dir = dir.canonicalPath(); + if (dir.isRoot() || dir.path() == QDir::home().canonicalPath()) { + qCritical() << "Attempt to remove root/home directory" << dir; + return false; + } + const QStringList fileNames = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); + for (const QString &fileName : fileNames) { + if (!removeRecursively(filePath + QLatin1Char('/') + fileName)) { + return false; + } + } + if (!QDir::root().rmdir(dir.path())) { + return false; + } + } else if (!QFile::remove(filePath)) { return false; } + return true; } -void QzTools::removeDir(const QString &d) +bool QzTools::copyRecursively(const QString &sourcePath, const QString &targetPath) { - QDir dir(d); - if (dir.exists()) { - const QFileInfoList list = dir.entryInfoList(); - QFileInfo fi; - for (int l = 0; l < list.size(); l++) { - fi = list.at(l); - if (fi.isDir() && fi.fileName() != QLatin1String(".") && fi.fileName() != QLatin1String("..")) { - QzTools::removeDir(fi.absoluteFilePath()); - } - else if (fi.isFile()) { - QzTools::removeFile(fi.absoluteFilePath()); + const QFileInfo srcFileInfo(sourcePath); + if (srcFileInfo.isDir() && !srcFileInfo.isSymLink()) { + QDir targetDir(targetPath); + targetDir.cdUp(); + if (!targetDir.mkdir(QFileInfo(targetPath).fileName())) { + return false; + } + const QStringList fileNames = QDir(sourcePath).entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); + for (const QString &fileName : fileNames) { + const QString newSourcePath = sourcePath + QL1C('/') + fileName; + const QString newTargetPath = targetPath + QL1C('/') + fileName; + if (!copyRecursively(newSourcePath, newTargetPath)) { + return false; } - } - dir.rmdir(d); +#ifndef Q_OS_WIN + } else if (srcFileInfo.isSymLink()) { + const QByteArray pathData = sourcePath.toLocal8Bit(); + char buf[1024]; + ssize_t len = readlink(pathData.constData(), buf, sizeof(buf) - 1); + if (len < 0) { + qWarning() << "Error getting symlink path" << pathData; + return false; + } + buf[len] = '\0'; + return QFile::link(QString::fromLocal8Bit(buf), targetPath); +#endif + } else if (!QFile::copy(sourcePath, targetPath)) { + return false; } + return true; } /* Finds same part of @one in @other from the beginning */ QString QzTools::samePartOfStrings(const QString &one, const QString &other) { int maxSize = qMin(one.size(), other.size()); if (maxSize <= 0) { return QString(); } int i = 0; while (one.at(i) == other.at(i)) { i++; if (i == maxSize) { break; } } return one.left(i); } QString QzTools::urlEncodeQueryString(const QUrl &url) { QString returnString = url.toString(QUrl::RemoveQuery | QUrl::RemoveFragment); if (url.hasQuery()) { returnString += QLatin1Char('?') + url.query(QUrl::FullyEncoded); } if (url.hasFragment()) { returnString += QLatin1Char('#') + url.fragment(QUrl::FullyEncoded); } returnString.replace(QLatin1Char(' '), QLatin1String("%20")); return returnString; } QString QzTools::fromPunycode(const QString &str) { if (!str.startsWith(QL1S("xn--"))) return str; // QUrl::fromAce will only decode domains from idn whitelist const QString decoded = QUrl::fromAce(str.toUtf8() + QByteArray(".org")); return decoded.left(decoded.size() - 4); } QString QzTools::escapeSqlGlobString(QString urlString) { urlString.replace(QL1C('['), QStringLiteral("[[")); urlString.replace(QL1C(']'), QStringLiteral("[]]")); urlString.replace(QStringLiteral("[["), QStringLiteral("[[]")); urlString.replace(QL1C('*'), QStringLiteral("[*]")); urlString.replace(QL1C('?'), QStringLiteral("[?]")); return urlString; } QString QzTools::ensureUniqueFilename(const QString &name, const QString &appendFormat) { Q_ASSERT(appendFormat.contains(QL1S("%1"))); QFileInfo info(name); if (!info.exists()) return name; const QDir dir = info.absoluteDir(); const QString fileName = info.fileName(); int i = 1; while (info.exists()) { QString file = fileName; int index = file.lastIndexOf(QL1C('.')); const QString appendString = appendFormat.arg(i); if (index == -1) file.append(appendString); else file = file.left(index) + appendString + file.mid(index); info.setFile(dir, file); i++; } return info.absoluteFilePath(); } QString QzTools::getFileNameFromUrl(const QUrl &url) { QString fileName = url.toString(QUrl::RemoveFragment | QUrl::RemoveQuery | QUrl::RemoveScheme | QUrl::RemovePort); if (fileName.endsWith(QLatin1Char('/'))) { fileName = fileName.mid(0, fileName.length() - 1); } if (fileName.indexOf(QLatin1Char('/')) != -1) { int pos = fileName.lastIndexOf(QLatin1Char('/')); fileName = fileName.mid(pos); fileName.remove(QLatin1Char('/')); } fileName = filterCharsFromFilename(fileName); if (fileName.isEmpty()) { fileName = filterCharsFromFilename(url.host()); } return fileName; } QString QzTools::filterCharsFromFilename(const QString &name) { QString value = name; value.replace(QLatin1Char('/'), QLatin1Char('-')); value.remove(QLatin1Char('\\')); value.remove(QLatin1Char(':')); value.remove(QLatin1Char('*')); value.remove(QLatin1Char('?')); value.remove(QLatin1Char('"')); value.remove(QLatin1Char('<')); value.remove(QLatin1Char('>')); value.remove(QLatin1Char('|')); return value; } QString QzTools::lastPathForFileDialog(const QString &dialogName, const QString &fallbackPath) { Settings settings; settings.beginGroup("LastFileDialogsPaths"); QString path = settings.value("FileDialogs/" + dialogName).toString(); settings.endGroup(); return path.isEmpty() ? fallbackPath : path; } void QzTools::saveLastPathForFileDialog(const QString &dialogName, const QString &path) { if (path.isEmpty()) { return; } Settings settings; settings.beginGroup("LastFileDialogsPaths"); settings.setValue(dialogName, path); settings.endGroup(); } QString QzTools::alignTextToWidth(const QString &string, const QString &text, const QFontMetrics &metrics, int width) { int pos = 0; QString returnString; while (pos <= string.size()) { QString part = string.mid(pos); QString elidedLine = metrics.elidedText(part, Qt::ElideRight, width); if (elidedLine.isEmpty()) { break; } if (elidedLine.size() != part.size()) { elidedLine = elidedLine.left(elidedLine.size() - 3); } if (!returnString.isEmpty()) { returnString += text; } returnString += elidedLine; pos += elidedLine.size(); } return returnString; } QString QzTools::fileSizeToString(qint64 size) { if (size < 0) { return QObject::tr("Unknown size"); } double _size = size / 1024.0; // KB if (_size < 1000) { return QString::number(_size > 1 ? _size : 1, 'f', 0) + " " + QObject::tr("KB"); } _size /= 1024; // MB if (_size < 1000) { return QString::number(_size, 'f', 1) + " " + QObject::tr("MB"); } _size /= 1024; // GB return QString::number(_size, 'f', 2) + " " + QObject::tr("GB"); } QPixmap QzTools::createPixmapForSite(const QIcon &icon, const QString &title, const QString &url) { const QFontMetrics fontMetrics = QApplication::fontMetrics(); const int padding = 4; const int maxWidth = fontMetrics.width(title.length() > url.length() ? title : url) + 3 * padding + 16; const int width = qMin(maxWidth, 150); const int height = fontMetrics.height() * 2 + fontMetrics.leading() + 2 * padding; QPixmap pixmap(width * qApp->devicePixelRatio(), height * qApp->devicePixelRatio()); pixmap.setDevicePixelRatio(qApp->devicePixelRatio()); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); // Draw background QPen pen(Qt::black); pen.setWidth(1); painter.setPen(pen); QPainterPath path; path.addRect(QRect(0, 0, width, height)); painter.fillPath(path, Qt::white); painter.drawPath(path); // Draw icon QRect iconRect(padding, 0, 16, height); icon.paint(&painter, iconRect); // Draw title QRect titleRect(iconRect.right() + padding, padding, width - padding - iconRect.right(), fontMetrics.height()); painter.drawText(titleRect, fontMetrics.elidedText(title, Qt::ElideRight, titleRect.width())); // Draw url QRect urlRect(titleRect.x(), titleRect.bottom() + fontMetrics.leading(), titleRect.width(), titleRect.height()); painter.setPen(QApplication::palette().color(QPalette::Link)); painter.drawText(urlRect, fontMetrics.elidedText(url, Qt::ElideRight, urlRect.width())); return pixmap; } QString QzTools::applyDirectionToPage(QString &pageContents) { QString direction = QLatin1String("ltr"); QString right_str = QLatin1String("right"); QString left_str = QLatin1String("left"); if (QApplication::isRightToLeft()) { direction = QLatin1String("rtl"); right_str = QLatin1String("left"); left_str = QLatin1String("right"); } pageContents.replace(QLatin1String("%DIRECTION%"), direction); pageContents.replace(QLatin1String("%RIGHT_STR%"), right_str); pageContents.replace(QLatin1String("%LEFT_STR%"), left_str); return pageContents; } QString QzTools::truncatedText(const QString &text, int size) { if (text.length() > size) { return text.left(size) + QL1S(".."); } return text; } // Thanks to http://www.qtcentre.org/threads/3205-Toplevel-widget-with-rounded-corners?p=17492#post17492 QRegion QzTools::roundedRect(const QRect &rect, int radius) { QRegion region; // middle and borders region += rect.adjusted(radius, 0, -radius, 0); region += rect.adjusted(0, radius, 0, -radius); // top left QRect corner(rect.topLeft(), QSize(radius * 2, radius * 2)); region += QRegion(corner, QRegion::Ellipse); // top right corner.moveTopRight(rect.topRight()); region += QRegion(corner, QRegion::Ellipse); // bottom left corner.moveBottomLeft(rect.bottomLeft()); region += QRegion(corner, QRegion::Ellipse); // bottom right corner.moveBottomRight(rect.bottomRight()); region += QRegion(corner, QRegion::Ellipse); return region; } QIcon QzTools::iconFromFileName(const QString &fileName) { static QHash iconCache; QFileInfo tempInfo(fileName); if (iconCache.contains(tempInfo.suffix())) { return iconCache.value(tempInfo.suffix()); } QFileIconProvider iconProvider; QTemporaryFile tempFile(DataPaths::path(DataPaths::Temp) + "/XXXXXX." + tempInfo.suffix()); tempFile.open(); tempInfo.setFile(tempFile.fileName()); QIcon icon(iconProvider.icon(tempInfo)); iconCache.insert(tempInfo.suffix(), icon); return icon; } QString QzTools::resolveFromPath(const QString &name) { const QString path = qgetenv("PATH").trimmed(); if (path.isEmpty()) { return QString(); } QStringList dirs = path.split(QLatin1Char(':'), QString::SkipEmptyParts); foreach (const QString &dir, dirs) { QDir d(dir); if (d.exists(name)) { return d.absoluteFilePath(name); } } return QString(); } // http://stackoverflow.com/questions/1031645/how-to-detect-utf-8-in-plain-c bool QzTools::isUtf8(const char* string) { if (!string) { return 0; } const unsigned char* bytes = (const unsigned char*)string; while (*bytes) { if ((// ASCII bytes[0] == 0x09 || bytes[0] == 0x0A || bytes[0] == 0x0D || (0x20 <= bytes[0] && bytes[0] <= 0x7F) ) ) { bytes += 1; continue; } if ((// non-overlong 2-byte (0xC2 <= bytes[0] && bytes[0] <= 0xDF) && (0x80 <= bytes[1] && bytes[1] <= 0xBF) ) ) { bytes += 2; continue; } if ((// excluding overlongs bytes[0] == 0xE0 && (0xA0 <= bytes[1] && bytes[1] <= 0xBF) && (0x80 <= bytes[2] && bytes[2] <= 0xBF) ) || (// straight 3-byte ((0xE1 <= bytes[0] && bytes[0] <= 0xEC) || bytes[0] == 0xEE || bytes[0] == 0xEF) && (0x80 <= bytes[1] && bytes[1] <= 0xBF) && (0x80 <= bytes[2] && bytes[2] <= 0xBF) ) || (// excluding surrogates bytes[0] == 0xED && (0x80 <= bytes[1] && bytes[1] <= 0x9F) && (0x80 <= bytes[2] && bytes[2] <= 0xBF) ) ) { bytes += 3; continue; } if ((// planes 1-3 bytes[0] == 0xF0 && (0x90 <= bytes[1] && bytes[1] <= 0xBF) && (0x80 <= bytes[2] && bytes[2] <= 0xBF) && (0x80 <= bytes[3] && bytes[3] <= 0xBF) ) || (// planes 4-15 (0xF1 <= bytes[0] && bytes[0] <= 0xF3) && (0x80 <= bytes[1] && bytes[1] <= 0xBF) && (0x80 <= bytes[2] && bytes[2] <= 0xBF) && (0x80 <= bytes[3] && bytes[3] <= 0xBF) ) || (// plane 16 bytes[0] == 0xF4 && (0x80 <= bytes[1] && bytes[1] <= 0x8F) && (0x80 <= bytes[2] && bytes[2] <= 0xBF) && (0x80 <= bytes[3] && bytes[3] <= 0xBF) ) ) { bytes += 4; continue; } return false; } return true; } bool QzTools::containsSpace(const QString &str) { Q_FOREACH (const QChar &c, str) { if (c.isSpace()) return true; } return false; } QString QzTools::getExistingDirectory(const QString &name, QWidget* parent, const QString &caption, const QString &dir, QFileDialog::Options options) { Settings settings; settings.beginGroup("FileDialogPaths"); QString lastDir = settings.value(name, dir).toString(); QString path = QFileDialog::getExistingDirectory(parent, caption, lastDir, options); if (!path.isEmpty()) { settings.setValue(name, QFileInfo(path).absolutePath()); } settings.endGroup(); return path; } static QString getFilename(const QString &path) { QFileInfo info(path); if (info.isFile()) { return info.fileName(); } if (info.isDir()) { return QString(); } if (info.dir().exists()) { return info.fileName(); } return QString(); } QString QzTools::getOpenFileName(const QString &name, QWidget* parent, const QString &caption, const QString &dir, const QString &filter, QString* selectedFilter, QFileDialog::Options options) { Settings settings; settings.beginGroup("FileDialogPaths"); QString lastDir = settings.value(name, QString()).toString(); QString fileName = getFilename(dir); if (lastDir.isEmpty()) { lastDir = dir; } else { lastDir.append(QDir::separator() + fileName); } QString path = QFileDialog::getOpenFileName(parent, caption, lastDir, filter, selectedFilter, options); if (!path.isEmpty()) { settings.setValue(name, QFileInfo(path).absolutePath()); } settings.endGroup(); return path; } QStringList QzTools::getOpenFileNames(const QString &name, QWidget* parent, const QString &caption, const QString &dir, const QString &filter, QString* selectedFilter, QFileDialog::Options options) { Settings settings; settings.beginGroup("FileDialogPaths"); QString lastDir = settings.value(name, QString()).toString(); QString fileName = getFilename(dir); if (lastDir.isEmpty()) { lastDir = dir; } else { lastDir.append(QDir::separator() + fileName); } QStringList paths = QFileDialog::getOpenFileNames(parent, caption, lastDir, filter, selectedFilter, options); if (!paths.isEmpty()) { settings.setValue(name, QFileInfo(paths.at(0)).absolutePath()); } settings.endGroup(); return paths; } QString QzTools::getSaveFileName(const QString &name, QWidget* parent, const QString &caption, const QString &dir, const QString &filter, QString* selectedFilter, QFileDialog::Options options) { Settings settings; settings.beginGroup("FileDialogPaths"); QString lastDir = settings.value(name, QString()).toString(); QString fileName = getFilename(dir); if (lastDir.isEmpty()) { lastDir = dir; } else { lastDir.append(QDir::separator() + fileName); } QString path = QFileDialog::getSaveFileName(parent, caption, lastDir, filter, selectedFilter, options); if (!path.isEmpty()) { settings.setValue(name, QFileInfo(path).absolutePath()); } settings.endGroup(); return path; } // Matches domain (assumes both pattern and domain not starting with dot) // pattern = domain to be matched // domain = site domain bool QzTools::matchDomain(const QString &pattern, const QString &domain) { if (pattern == domain) { return true; } if (!domain.endsWith(pattern)) { return false; } int index = domain.indexOf(pattern); return index > 0 && domain[index - 1] == QLatin1Char('.'); } QKeySequence QzTools::actionShortcut(QKeySequence shortcut, QKeySequence fallBack, QKeySequence shortcutRtl, QKeySequence fallbackRtl) { if (QApplication::isRightToLeft() && (!shortcutRtl.isEmpty() || !fallbackRtl.isEmpty())) return shortcutRtl.isEmpty() ? fallbackRtl : shortcutRtl; return shortcut.isEmpty() ? fallBack : shortcut; } static inline bool isQuote(const QChar &c) { return (c == QLatin1Char('"') || c == QLatin1Char('\'')); } // Function splits command line into arguments // eg. /usr/bin/foo -o test -b "bar bar" -s="sed sed" // => '/usr/bin/foo' '-o' 'test' '-b' 'bar bar' '-s=sed sed' QStringList QzTools::splitCommandArguments(const QString &command) { QString line = command.trimmed(); if (line.isEmpty()) { return QStringList(); } QChar SPACE(' '); QChar EQUAL('='); QChar BSLASH('\\'); QChar QUOTE('"'); QStringList r; int equalPos = -1; // Position of = in opt="value" int startPos = isQuote(line.at(0)) ? 1 : 0; bool inWord = !isQuote(line.at(0)); bool inQuote = !inWord; if (inQuote) { QUOTE = line.at(0); } const int strlen = line.length(); for (int i = 0; i < strlen; ++i) { const QChar c = line.at(i); if (inQuote && c == QUOTE && i > 0 && line.at(i - 1) != BSLASH) { QString str = line.mid(startPos, i - startPos); if (equalPos > -1) { str.remove(equalPos - startPos + 1, 1); } inQuote = false; if (!str.isEmpty()) { r.append(str); } continue; } else if (!inQuote && isQuote(c)) { inQuote = true; QUOTE = c; if (!inWord) { startPos = i + 1; } else if (i > 0 && line.at(i - 1) == EQUAL) { equalPos = i - 1; } } if (inQuote) { continue; } if (inWord && (c == SPACE || i == strlen - 1)) { int len = (i == strlen - 1) ? -1 : i - startPos; const QString str = line.mid(startPos, len); inWord = false; if (!str.isEmpty()) { r.append(str); } } else if (!inWord && c != SPACE) { inWord = true; startPos = i; } } // Unmatched quote if (inQuote) { return QStringList(); } return r; } bool QzTools::startExternalProcess(const QString &executable, const QString &args) { const QStringList arguments = splitCommandArguments(args); bool success = QProcess::startDetached(executable, arguments); if (!success) { QString info = "
  • %1%2
  • %3%4
"; info = info.arg(QObject::tr("Executable: "), executable, QObject::tr("Arguments: "), arguments.join(QLatin1String(" "))); QMessageBox::critical(0, QObject::tr("Cannot start external program"), QObject::tr("Cannot start external program! %1").arg(info)); } return success; } void QzTools::setWmClass(const QString &name, const QWidget* widget) { #ifdef QZ_WS_X11 if (QGuiApplication::platformName() != QL1S("xcb")) return; const QByteArray &nameData = name.toUtf8(); const QByteArray &classData = QByteArrayLiteral("Falkon"); uint32_t class_len = nameData.length() + 1 + classData.length() + 1; char *class_hint = (char*) malloc(class_len); qstrcpy(class_hint, nameData.constData()); qstrcpy(class_hint + nameData.length() + 1, classData.constData()); xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, widget->winId(), XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, class_len, class_hint); free(class_hint); #else Q_UNUSED(name) Q_UNUSED(widget) #endif } QString QzTools::operatingSystem() { #ifdef Q_OS_MACOS QString str = "Mac OS X"; SInt32 majorVersion; SInt32 minorVersion; if (Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr && Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr) { str.append(QString(" %1.%2").arg(majorVersion).arg(minorVersion)); } return str; #endif #ifdef Q_OS_LINUX return "Linux"; #endif #ifdef Q_OS_BSD4 return "BSD 4.4"; #endif #ifdef Q_OS_BSDI return "BSD/OS"; #endif #ifdef Q_OS_FREEBSD return "FreeBSD"; #endif #ifdef Q_OS_HPUX return "HP-UX"; #endif #ifdef Q_OS_HURD return "GNU Hurd"; #endif #ifdef Q_OS_LYNX return "LynxOS"; #endif #ifdef Q_OS_NETBSD return "NetBSD"; #endif #ifdef Q_OS_OS2 return "OS/2"; #endif #ifdef Q_OS_OPENBSD return "OpenBSD"; #endif #ifdef Q_OS_OSF return "HP Tru64 UNIX"; #endif #ifdef Q_OS_SOLARIS return "Sun Solaris"; #endif #ifdef Q_OS_UNIXWARE return "UnixWare 7 / Open UNIX 8"; #endif #ifdef Q_OS_UNIX return "Unix"; #endif #ifdef Q_OS_HAIKU return "Haiku"; #endif #ifdef Q_OS_WIN32 QString str = "Windows"; switch (QSysInfo::windowsVersion()) { case QSysInfo::WV_NT: str.append(" NT"); break; case QSysInfo::WV_2000: str.append(" 2000"); break; case QSysInfo::WV_XP: str.append(" XP"); break; case QSysInfo::WV_2003: str.append(" XP Pro x64"); break; case QSysInfo::WV_VISTA: str.append(" Vista"); break; case QSysInfo::WV_WINDOWS7: str.append(" 7"); break; case QSysInfo::WV_WINDOWS8: str.append(" 8"); break; case QSysInfo::WV_WINDOWS8_1: str.append(" 8.1"); break; case QSysInfo::WV_WINDOWS10: str.append(" 10"); break; default: break; } return str; #endif } QString QzTools::cpuArchitecture() { return QSysInfo::currentCpuArchitecture(); } QString QzTools::operatingSystemLong() { const QString arch = cpuArchitecture(); if (arch.isEmpty()) return QzTools::operatingSystem(); return QzTools::operatingSystem() + QSL(" ") + arch; } diff --git a/src/lib/tools/qztools.h b/src/lib/tools/qztools.h index 59de3042..47d4b631 100644 --- a/src/lib/tools/qztools.h +++ b/src/lib/tools/qztools.h @@ -1,100 +1,100 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2016 David Rosca * * 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 . * ============================================================ */ #ifndef QZTOOLS_H #define QZTOOLS_H #include #include "qzcommon.h" class QSslCertificate; class QFontMetrics; class QPixmap; class QIcon; class QWidget; class QUrl; class FALKON_EXPORT QzTools { public: static QByteArray pixmapToByteArray(const QPixmap &pix); static QPixmap pixmapFromByteArray(const QByteArray &data); static QUrl pixmapToDataUrl(const QPixmap &pix); static QPixmap dpiAwarePixmap(const QString &path); static QString readAllFileContents(const QString &filename); static QByteArray readAllFileByteContents(const QString &filename); static void centerWidgetOnScreen(QWidget* w); static void centerWidgetToParent(QWidget* w, QWidget* parent); - static bool removeFile(const QString &fullFileName); - static void removeDir(const QString &d); + static bool removeRecursively(const QString &filePath); + static bool copyRecursively(const QString &sourcePath, const QString &targetPath); static QString samePartOfStrings(const QString &one, const QString &other); static QString urlEncodeQueryString(const QUrl &url); static QString fromPunycode(const QString &str); static QString escapeSqlGlobString(QString urlString); static QString ensureUniqueFilename(const QString &name, const QString &appendFormat = QString("(%1)")); static QString getFileNameFromUrl(const QUrl &url); static QString filterCharsFromFilename(const QString &name); static QString lastPathForFileDialog(const QString &dialogName, const QString &fallbackPath); static void saveLastPathForFileDialog(const QString &dialogName, const QString &path); static QString alignTextToWidth(const QString &string, const QString &text, const QFontMetrics &metrics, int width); static QString fileSizeToString(qint64 size); static QPixmap createPixmapForSite(const QIcon &icon, const QString &title, const QString &url); static QString applyDirectionToPage(QString &pageContents); static QString truncatedText(const QString &text, int size); static QString resolveFromPath(const QString &name); static QStringList splitCommandArguments(const QString &command); static bool startExternalProcess(const QString &executable, const QString &args); static QRegion roundedRect(const QRect &rect, int radius); static QIcon iconFromFileName(const QString &fileName); static bool isUtf8(const char* string); static bool containsSpace(const QString &str); // QFileDialog static functions that remembers last used directory static QString getExistingDirectory(const QString &name, QWidget* parent = 0, const QString &caption = QString(), const QString &dir = QString(), QFileDialog::Options options = QFileDialog::ShowDirsOnly); static QString getOpenFileName(const QString &name, QWidget* parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString* selectedFilter = 0, QFileDialog::Options options = 0); static QStringList getOpenFileNames(const QString &name, QWidget* parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString* selectedFilter = 0, QFileDialog::Options options = 0); static QString getSaveFileName(const QString &name, QWidget* parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString* selectedFilter = 0, QFileDialog::Options options = 0); static bool matchDomain(const QString &pattern, const QString &domain); static QKeySequence actionShortcut(QKeySequence shortcut, QKeySequence fallBack, QKeySequence shortcutRtl = QKeySequence(), QKeySequence fallbackRtl = QKeySequence()); static QString operatingSystem(); static QString cpuArchitecture(); static QString operatingSystemLong(); static void setWmClass(const QString &name, const QWidget* widget); template static bool containsIndex(const T &container, int index) { return (index >= 0 && container.count() > index); } }; #endif // QZTOOLS_H