aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2017-12-08 14:22:19 +0100
committerAqua-sama <aqua@iserlohn-fortress.net>2017-12-08 14:22:19 +0100
commit4e3c479a0f279926e0bd9a359a0ee57b334e976e (patch)
tree068f1da93a4ff6dcce251f5152df16bf77be53a8
parentlibconfig test (diff)
downloadsmolbote-4e3c479a0f279926e0bd9a359a0ee57b334e976e.tar.xz
Replaced tinytoml with libconfig
-rw-r--r--data/poi.cfg58
-rw-r--r--data/poi.toml86
-rw-r--r--data/resources.qrc2
-rw-r--r--lib/settings/configuration.cpp70
-rw-r--r--lib/settings/configuration.h11
-rw-r--r--lib/settings/settings.qbs1
-rw-r--r--smolbote.qbs28
-rw-r--r--src/3rd-party/toml/LICENSE24
-rw-r--r--src/3rd-party/toml/toml.h1958
-rw-r--r--src/browser.cpp222
-rw-r--r--src/browser.h59
-rw-r--r--src/forms/aboutdialog.cpp64
-rw-r--r--src/forms/aboutdialog.h4
-rw-r--r--src/forms/profilesdialog.cpp22
-rw-r--r--src/forms/profilesdialog.h2
-rw-r--r--src/main.cpp175
-rw-r--r--src/mainwindow.cpp52
-rw-r--r--src/mainwindow.h8
-rw-r--r--src/singleapplication.cpp8
-rw-r--r--src/singleapplication.h2
-rw-r--r--src/webengine/webengineprofile.cpp157
-rw-r--r--src/webengine/webengineprofile.h7
-rw-r--r--src/widgets/mainwindowmenubar.cpp58
-rw-r--r--src/widgets/mainwindowmenubar.h8
-rw-r--r--src/widgets/webviewtabbar.cpp7
25 files changed, 503 insertions, 2590 deletions
diff --git a/data/poi.cfg b/data/poi.cfg
new file mode 100644
index 0000000..68503e1
--- /dev/null
+++ b/data/poi.cfg
@@ -0,0 +1,58 @@
+// smolbote default configuration file
+// Uses libconfig format, for details refer to:
+// https://hyperrealm.github.io/libconfig/libconfig_manual.html#Configuration-Files
+
+// Browser default settings
+browser = {
+ // true to generate user settings when run
+ firstRun = true;
+
+ // default profile name the browser should use; "" is off-the-record
+ profile = "";
+
+ // default window size
+ window = {
+ height = 720;
+ width = 1280;
+ maximized = true;
+ title = "title — smolbote [profile]";
+ };
+
+ ui = {
+ navtoolbarMovable = false;
+ tabtoolbarMovable = false;
+ };
+
+ shortcuts = {
+ // browser menu
+ newWindow = "Ctrl+N";
+ newTab = "Ctrl+T";
+ about = "F1";
+ quit = "Ctrl+Q";
+
+ focusAddress = "F4";
+ fullscreen = "F11";
+
+ // tabs
+ tabClose = "Ctrl+X";
+ tabLeft = "Shift+Left";
+ tabRight = "Shift+Right";
+ };
+};
+
+// Profile settings
+profile = {
+ path = "~/.config/smolbote/Profiles";
+ homepage = "about:blank";
+ newtab = "about:blank";
+};
+
+// Bookmark settings
+bookmarks = {
+ path = "~/.config/smolbote/bookmarks.xbel";
+};
+
+// Downloads settings
+downloads = {
+ path = "~/Downloads"
+};
diff --git a/data/poi.toml b/data/poi.toml
deleted file mode 100644
index 4a84692..0000000
--- a/data/poi.toml
+++ /dev/null
@@ -1,86 +0,0 @@
-#
-# poi.conf
-#
-## Settings and default settings
-# There are two parts to the settings - default values and user overrides.
-# The default settings are read from:
-# - /usr/local/share/smolbote/poi.conf
-# - /usr/share/smolbote/poi.conf
-# - /etc/smolbote.d/poi.conf
-# - :/poi.toml
-# The user settings are read from:
-# - any location specified with -c/--config
-# - QStandardPaths::AppConfigLocation + "/poi.conf"
-#
-## Variables
-# §home is QStandardPaths::HomeLocation, usually /home/username
-# $cache is QStandardPaths::CacheLocation, usually /home/username/.cache/smolbote
-# $settings is the directory where the settings file is located, usually /home/username/.config/smolbote
-
-# General
-[general]
-search="https://duckduckgo.com/?q=$term" # FIXME remove; move to profile
-
-# Browser: application-wide settings
-[browser]
-#sessionPath="$cache/session.json"
-
-# Profile
-[browser.profile]
-# Which profile should be used by default for new windows
-# A nameless ("") profile is off-the-record
-default=""
-# Where to look for profiles
-path="$home/.config/smolbote/profiles/"
-storagePath="$home/.config/smolbote/profiles/"
-cachePath="$home/.cache/smolbote/profiles/"
-
-[browser.profile.new]
-homepage="https://duckduckgo.com"
-newtab="about:blank"
-search="https://duckduckgo.com/lite?q=$term" # FIXME
-
-# Main window settings
-[window]
-height=720
-width=1280
-maximized=true
-title="title — smolbote [profile]"
-
-# Main window shortcuts
-[window.shortcuts]
-focusAddress="F4"
-fullscreen="F11"
-tabNew="Ctrl+T"
-tabClose="Ctrl+X"
-tabLeft="Shift+Left"
-tabRight="Shift+Right"
-windowNew="Ctrl+N"
-windowClose="Ctrl+Q"
-
-# Main window UI
-[window.ui]
-navtoolbarMovable=false
-tabtoolbarMovable=false
-
-# URL blocker
-[blocker]
-shortcut="Ctrl+Shift+F"
-path="$settings/"
-subscriptions=[
- "filter.json"
-# "https://easylist.to/easylist/easylist.txt",
-# "https://easylist-downloads.adblockplus.org/easylist_noelemhide.txt",
-# "https://easylist.to/easylist/easyprivacy.txt"
-]
-
-# Bookmark manager
-[bookmarks]
-dialogShortcut="Ctrl+Shift+B"
-path="$settings/bookmarks.xbel"
-
-# Download manager
-[downloads]
-dialogShortcut="Ctrl+Shift+D"
-path="$home/Downloads"
-auto=false
diff --git a/data/resources.qrc b/data/resources.qrc
index b2b6be5..529bf43 100644
--- a/data/resources.qrc
+++ b/data/resources.qrc
@@ -1,6 +1,6 @@
<RCC>
<qresource prefix="/">
<file alias="icon.svg">poi.svg</file>
- <file>poi.toml</file>
+ <file>poi.cfg</file>
</qresource>
</RCC>
diff --git a/lib/settings/configuration.cpp b/lib/settings/configuration.cpp
index 543ea60..9d53581 100644
--- a/lib/settings/configuration.cpp
+++ b/lib/settings/configuration.cpp
@@ -22,10 +22,18 @@
#include <libconfig.h++>
#include <sstream>
+using namespace libconfig;
+
Configuration::Configuration()
{
- m_userCfg = new libconfig::Config();
- m_defaultCfg = new libconfig::Config();
+ m_userCfg = new Config();
+#ifdef C_LIKE_CONFIG
+ m_userCfg->setOptions(Config::OptionSemicolonSeparators | Config::OptionOpenBraceOnSeparateLine);
+#endif
+ // fsync after writing and before closing
+ m_userCfg->setOption(Config::OptionFsync, true);
+
+ m_defaultCfg = new Config();
}
Configuration::~Configuration()
@@ -43,19 +51,30 @@ bool Configuration::readUserConfiguration(const std::string &path)
m_userCfgPath = path;
try {
m_userCfg->readFile(path.c_str());
- } catch (libconfig::FileIOException) {
+ } catch (FileIOException) {
return false;
- } catch (libconfig::ParseException) {
+ } catch (ParseException) {
return false;
}
return true;
}
+bool Configuration::writeUserConfiguration(const std::string &path)
+{
+ m_userCfgPath = path;
+ try {
+ m_userCfg->writeFile(path.c_str());
+ } catch (FileIOException) {
+ return false;
+ }
+ return true;
+}
+
bool Configuration::readDefaultConfiguration(const std::string &data)
{
try {
m_defaultCfg->readString(data);
- } catch(libconfig::ParseException) {
+ } catch(ParseException) {
return false;
}
return true;
@@ -64,7 +83,7 @@ bool Configuration::readDefaultConfiguration(const std::string &data)
std::vector<std::string> Configuration::children(const char* name)
{
std::vector<std::string> groupNames;
- const libconfig::Setting &root = m_defaultCfg->lookup(name);
+ const Setting &root = m_defaultCfg->lookup(name);
for(auto i = root.begin(); i != root.end(); ++i) {
groupNames.push_back(std::string(i->getName()));
@@ -76,23 +95,23 @@ std::vector<std::string> Configuration::children(const char* name)
template<typename T>
std::optional<T> Configuration::value(const char* path) const
{
- libconfig::Config *conf = getConfig(path);
+ Config *conf = getConfig(path);
if(conf == nullptr) {
return std::nullopt;
}
// setting was found
- const libconfig::Setting &setting = conf->lookup(path);
+ const Setting &setting = conf->lookup(path);
std::optional<T> r;
// cast depending on type
// type checks are done during compile time
switch (setting.getType()) {
- case libconfig::Setting::TypeNone:
+ case Setting::TypeNone:
r = std::nullopt;
break;
- case libconfig::Setting::TypeInt:
+ case Setting::TypeInt:
// int, unsigned int, long, unsigned long
if constexpr(std::is_same_v<T, std::string>) {
r = std::optional<std::string>(std::to_string(static_cast<int>(setting)));
@@ -103,7 +122,7 @@ std::optional<T> Configuration::value(const char* path) const
}
break;
- case libconfig::Setting::TypeInt64:
+ case Setting::TypeInt64:
// int, unsigned int; long long, unsigned long long
if constexpr(std::is_same_v<T, std::string>) {
r = std::optional<std::string>(std::to_string(static_cast<long long>(setting)));
@@ -114,7 +133,7 @@ std::optional<T> Configuration::value(const char* path) const
}
break;
- case libconfig::Setting::TypeFloat:
+ case Setting::TypeFloat:
// float, double
if constexpr(std::is_same_v<T, std::string>) {
r = std::optional<std::string>(std::to_string(static_cast<float>(setting)));
@@ -125,7 +144,7 @@ std::optional<T> Configuration::value(const char* path) const
}
break;
- case libconfig::Setting::TypeString:
+ case Setting::TypeString:
// const char*, std::string
if constexpr(std::is_same<T, std::string>::value) {
r = std::optional<std::string>(static_cast<const char*>(setting));
@@ -134,7 +153,7 @@ std::optional<T> Configuration::value(const char* path) const
}
break;
- case libconfig::Setting::TypeBoolean:
+ case Setting::TypeBoolean:
// bool
if constexpr(std::is_same<T, std::string>::value) {
r = std::optional<std::string>(static_cast<bool>(setting) ? "true" : "false");
@@ -145,15 +164,15 @@ std::optional<T> Configuration::value(const char* path) const
}
break;
- case libconfig::Setting::TypeGroup:
+ case Setting::TypeGroup:
r = std::nullopt;
break;
- case libconfig::Setting::TypeArray:
+ case Setting::TypeArray:
r = std::nullopt;
break;
- case libconfig::Setting::TypeList:
+ case Setting::TypeList:
r = std::nullopt;
break;
}
@@ -181,7 +200,7 @@ template<typename T>
void Configuration::setValue(std::string path, const T &val)
{
if(m_userCfg->exists(path)) {
- libconfig::Setting &setting = m_userCfg->lookup(path);
+ Setting &setting = m_userCfg->lookup(path);
// compiler complained about operator= not taking unsinged ints, longs and long longs
if constexpr(std::is_unsigned_v<T> && !std::is_same_v<T, bool>) {
setting = static_cast<typename std::make_signed_t<T>>(val);
@@ -197,8 +216,8 @@ void Configuration::setValue(std::string path, const T &val)
// this will error out if entry being added is not in the default config
std::istringstream p(path);
- libconfig::Setting *userSetting = &m_userCfg->getRoot();
- libconfig::Setting *defaultSetting = &m_defaultCfg->getRoot();
+ Setting *userSetting = &m_userCfg->getRoot();
+ Setting *defaultSetting = &m_defaultCfg->getRoot();
std::string i;
while (std::getline(p, i, '.')) {
@@ -232,7 +251,7 @@ template void Configuration::setValue<bool>(std::string path, const bool &val);
template void Configuration::setValue<std::string>(std::string path, const std::string &val);
-libconfig::Config *Configuration::getConfig(const char* path) const
+Config *Configuration::getConfig(const char* path) const
{
if(m_userCfg->exists(path)) {
return m_userCfg;
@@ -242,3 +261,12 @@ libconfig::Config *Configuration::getConfig(const char* path) const
return nullptr;
}
}
+
+std::string &patchHome(std::string &path, const std::string &home)
+{
+ const size_t location = path.find("~");
+ if(location != std::string::npos) {
+ return path.replace(location, 1, home);
+ }
+ return path;
+}
diff --git a/lib/settings/configuration.h b/lib/settings/configuration.h
index e0f1872..548b816 100644
--- a/lib/settings/configuration.h
+++ b/lib/settings/configuration.h
@@ -18,8 +18,8 @@
**
******************************************************************************/
-#ifndef SETTINGS_H
-#define SETTINGS_H
+#ifndef CONFIGURATION_H
+#define CONFIGURATION_H
#include <optional>
#include <vector>
@@ -36,6 +36,8 @@ public:
~Configuration();
bool readUserConfiguration(const std::string &path);
+ bool writeUserConfiguration(const std::string &path);
+
bool readDefaultConfiguration(const std::string &data);
std::vector<std::string> children(const char *name = "");
@@ -54,6 +56,9 @@ private:
libconfig::Config *m_defaultCfg;
};
+// replace ~ with home
+std::string& patchHome(std::string &path, const std::string &home);
+
// instantiate functions
// this needs to be done because the implementation is in the cpp file
@@ -89,4 +94,4 @@ extern template void Configuration::setValue<bool>(std::string path, const bool
extern template void Configuration::setValue<std::string>(std::string path, const std::string &val);
-#endif // SETTINGS_H
+#endif // CONFIGURATION_H
diff --git a/lib/settings/settings.qbs b/lib/settings/settings.qbs
index e49339f..77e97fb 100644
--- a/lib/settings/settings.qbs
+++ b/lib/settings/settings.qbs
@@ -8,6 +8,7 @@ Project {
Depends { name: "cpp" }
+ cpp.defines: "C_LIKE_CONFIG"
cpp.cxxLanguageVersion: "c++17"
files: [
diff --git a/smolbote.qbs b/smolbote.qbs
index 6d991eb..d18af60 100644
--- a/smolbote.qbs
+++ b/smolbote.qbs
@@ -49,6 +49,9 @@ Project {
Depends {
name: "downloads"
}
+ Depends {
+ name: "settings"
+ }
Probe {
id: git
@@ -65,24 +68,23 @@ Project {
}
// global includes
- cpp.includePaths: ['src', 'src/3rd-party', 'src/lib']
+ cpp.includePaths: ['src', 'src/3rd-party', 'src/lib', 'lib']
// global defines
cpp.defines: {
if(project.deprecatedWarnings)
defines.push("QT_DEPRECATED_WARNINGS", "QT_DISABLE_DEPRECATED_BEFORE="+project.deprecatedBefore);
return defines;
}
- cpp.cxxLanguageVersion: "c++11"
+ cpp.cxxLanguageVersion: "c++17"
+
+ cpp.linkerFlags: libconfig.libs
Group {
name: "main"
files: [
"src/browser.cpp",
"src/browser.h",
- "src/interfaces.h",
"src/main.cpp",
- "src/settings.cpp",
- "src/settings.h",
"src/singleapplication.cpp",
"src/singleapplication.h",
]
@@ -114,7 +116,7 @@ Project {
"src/widgets/webviewtabbar.h",
]
}
-
+/*
Group {
name: "Request Filter"
files: [
@@ -140,7 +142,7 @@ Project {
return defines;
}
}
-
+*/
Group {
name: "Profile"
files: [
@@ -168,18 +170,6 @@ Project {
qbs.install: true
qbs.installDir: "bin"
}
-
- Group {
- name: "Configuration"
- files: [
- "data/poi.toml",
- ]
- qbs.install: true
- qbs.installDir: "share/smolbote"
- }
} // CppApplication poi
- //SubProject {
- // filePath: "src/plugins/plugins.qbs"
- //}
}
diff --git a/src/3rd-party/toml/LICENSE b/src/3rd-party/toml/LICENSE
deleted file mode 100644
index 1514196..0000000
--- a/src/3rd-party/toml/LICENSE
+++ /dev/null
@@ -1,24 +0,0 @@
-Copyright (c) 2014, MAYAH
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/src/3rd-party/toml/toml.h b/src/3rd-party/toml/toml.h
deleted file mode 100644
index ec8c489..0000000
--- a/src/3rd-party/toml/toml.h
+++ /dev/null
@@ -1,1958 +0,0 @@
-#ifndef TINYTOML_H_
-#define TINYTOML_H_
-
-#include <algorithm>
-#include <cassert>
-#include <cctype>
-#include <chrono>
-#include <cmath>
-#include <cstdint>
-#include <cstdio>
-#include <ctime>
-#include <iomanip>
-#include <istream>
-#include <sstream>
-#include <stdexcept>
-#include <string>
-#include <map>
-#include <memory>
-#include <utility>
-#include <vector>
-
-namespace toml {
-
-// ----------------------------------------------------------------------
-// Declarations
-
-class Value;
-typedef std::chrono::system_clock::time_point Time;
-typedef std::vector<Value> Array;
-typedef std::map<std::string, Value> Table;
-
-namespace internal {
-template<typename T> struct call_traits_value {
- typedef T return_type;
-};
-template<typename T> struct call_traits_ref {
- typedef const T& return_type;
-};
-} // namespace internal
-
-template<typename T> struct call_traits;
-template<> struct call_traits<bool> : public internal::call_traits_value<bool> {};
-template<> struct call_traits<int> : public internal::call_traits_value<int> {};
-template<> struct call_traits<int64_t> : public internal::call_traits_value<int64_t> {};
-template<> struct call_traits<double> : public internal::call_traits_value<double> {};
-template<> struct call_traits<std::string> : public internal::call_traits_ref<std::string> {};
-template<> struct call_traits<Time> : public internal::call_traits_ref<Time> {};
-template<> struct call_traits<Array> : public internal::call_traits_ref<Array> {};
-template<> struct call_traits<Table> : public internal::call_traits_ref<Table> {};
-
-// A value is returned for std::vector<T>. Not reference.
-// This is because a fresh vector is made.
-template<typename T> struct call_traits<std::vector<T>> : public internal::call_traits_value<std::vector<T>> {};
-
-// Formatting flags
-enum FormatFlag {
- FORMAT_NONE = 0,
- FORMAT_INDENT = 1
-};
-
-class Value {
-public:
- enum Type {
- NULL_TYPE,
- BOOL_TYPE,
- INT_TYPE,
- DOUBLE_TYPE,
- STRING_TYPE,
- TIME_TYPE,
- ARRAY_TYPE,
- TABLE_TYPE,
- };
-
- Value() : type_(NULL_TYPE), null_(nullptr) {}
- Value(bool v) : type_(BOOL_TYPE), bool_(v) {}
- Value(int v) : type_(INT_TYPE), int_(v) {}
- Value(int64_t v) : type_(INT_TYPE), int_(v) {}
- Value(double v) : type_(DOUBLE_TYPE), double_(v) {}
- Value(const std::string& v) : type_(STRING_TYPE), string_(new std::string(v)) {}
- Value(const char* v) : type_(STRING_TYPE), string_(new std::string(v)) {}
- Value(const Time& v) : type_(TIME_TYPE), time_(new Time(v)) {}
- Value(const Array& v) : type_(ARRAY_TYPE), array_(new Array(v)) {}
- Value(const Table& v) : type_(TABLE_TYPE), table_(new Table(v)) {}
- Value(std::string&& v) : type_(STRING_TYPE), string_(new std::string(std::move(v))) {}
- Value(Array&& v) : type_(ARRAY_TYPE), array_(new Array(std::move(v))) {}
- Value(Table&& v) : type_(TABLE_TYPE), table_(new Table(std::move(v))) {}
-
- Value(const Value& v);
- Value(Value&& v) noexcept;
- Value& operator=(const Value& v);
- Value& operator=(Value&& v) noexcept;
-
- // Guards from unexpected Value construction.
- // Someone might use a value like this:
- // toml::Value v = x->find("foo");
- // But this is wrong. Without this constructor,
- // value will be unexpectedly initialized with bool.
- Value(const void* v) = delete;
- ~Value();
-
- // Retruns Value size.
- // 0 for invalid value.
- // The number of inner elements for array or table.
- // 1 for other types.
- size_t size() const;
- bool empty() const;
- Type type() const { return type_; }
-
- bool valid() const { return type_ != NULL_TYPE; }
- template<typename T> bool is() const;
- template<typename T> typename call_traits<T>::return_type as() const;
-
- friend bool operator==(const Value& lhs, const Value& rhs);
- friend bool operator!=(const Value& lhs, const Value& rhs) { return !(lhs == rhs); }
-
- // ----------------------------------------------------------------------
- // For integer/floating value
-
- // Returns true if the value is int or double.
- bool isNumber() const;
- // Returns number. Convert to double.
- double asNumber() const;
-
- // ----------------------------------------------------------------------
- // For Time value
-
- // Converts to time_t if the internal value is Time.
- // We don't have as<std::time_t>(). Since time_t is basically signed long,
- // it's something like a method to converting to (normal) integer.
- std::time_t as_time_t() const;
-
- // ----------------------------------------------------------------------
- // For Table value
- template<typename T> typename call_traits<T>::return_type get(const std::string&) const;
- Value* set(const std::string& key, const Value& v);
- // Finds a Value with |key|. |key| can contain '.'
- // Note: if you would like to find a child value only, you need to use findChild.
- const Value* find(const std::string& key) const;
- Value* find(const std::string& key);
- bool has(const std::string& key) const { return find(key) != nullptr; }
- bool erase(const std::string& key);
-
- Value& operator[](const std::string& key);
-
- // Merge table. Returns true if succeeded. Otherwise, |this| might be corrupted.
- // When the same key exists, it will be overwritten.
- bool merge(const Value&);
-
- // Finds a value with |key|. It searches only children.
- Value* findChild(const std::string& key);
- const Value* findChild(const std::string& key) const;
- // Sets a value, and returns the pointer to the created value.
- // When the value having the same key exists, it will be overwritten.
- Value* setChild(const std::string& key, const Value& v);
- Value* setChild(const std::string& key, Value&& v);
- bool eraseChild(const std::string& key);
-
- // ----------------------------------------------------------------------
- // For Array value
-
- template<typename T> typename call_traits<T>::return_type get(size_t index) const;
- const Value* find(size_t index) const;
- Value* find(size_t index);
- Value* push(const Value& v);
- Value* push(Value&& v);
-
- // ----------------------------------------------------------------------
- // Others
-
- // Writer.
- static std::string spaces(int num);
- static std::string escapeKey(const std::string& key);
-
- void write(std::ostream*, const std::string& keyPrefix = std::string(), int indent = -1) const;
- void writeFormatted(std::ostream*, FormatFlag flags) const;
-
- friend std::ostream& operator<<(std::ostream&, const Value&);
-
-private:
- static const char* typeToString(Type);
-
- template<typename T> void assureType() const;
- Value* ensureValue(const std::string& key);
-
- template<typename T> struct ValueConverter;
-
- Type type_;
- union {
- void* null_;
- bool bool_;
- int64_t int_;
- double double_;
- std::string* string_;
- Time* time_;
- Array* array_;
- Table* table_;
- };
-
- template<typename T> friend struct ValueConverter;
-};
-
-// parse() returns ParseResult.
-struct ParseResult {
- ParseResult(toml::Value v, std::string er) :
- value(std::move(v)),
- errorReason(std::move(er)) {}
-
- bool valid() const { return value.valid(); }
-
- toml::Value value;
- std::string errorReason;
-};
-
-// Parses from std::istream.
-ParseResult parse(std::istream&);
-
-// ----------------------------------------------------------------------
-// Declarations for Implementations
-// You don't need to understand the below to use this library.
-
-#if defined(_WIN32)
-// Windows does not have timegm but have _mkgmtime.
-inline time_t timegm(std::tm* timeptr)
-{
- return _mkgmtime(timeptr);
-}
-#endif
-#if defined(_MSC_VER)
-// Visual studio doesn't define gmtime_r, but mingw does
-inline std::tm* gmtime_r(const time_t* timer, std::tm* result)
-{
- gmtime_s(result, timer);
- return result;
-}
-#endif
-
-namespace internal {
-
-enum class TokenType {
- ERROR,
- END_OF_FILE,
- END_OF_LINE,
- IDENT,
- STRING,
- MULTILINE_STRING,
- BOOL,
- INT,
- DOUBLE,
- TIME,
- COMMA,
- DOT,
- EQUAL,
- LBRACKET,
- RBRACKET,
- LBRACE,
- RBRACE,
-};
-
-class Token {
-public:
- explicit Token(TokenType type) : type_(type) {}
- Token(TokenType type, const std::string& v) : type_(type), str_value_(v) {}
- Token(TokenType type, bool v) : type_(type), int_value_(v) {}
- Token(TokenType type, std::int64_t v) : type_(type), int_value_(v) {}
- Token(TokenType type, double v) : type_(type), double_value_(v) {}
- Token(TokenType type, std::chrono::system_clock::time_point tp) : type_(type), time_value_(tp) {}
-
- TokenType type() const { return type_; }
- const std::string& strValue() const { return str_value_; }
- bool boolValue() const { return int_value_ != 0; }
- std::int64_t intValue() const { return int_value_; }
- double doubleValue() const { return double_value_; }
- std::chrono::system_clock::time_point timeValue() const { return time_value_; }
-
-private:
- TokenType type_;
- std::string str_value_;
- std::int64_t int_value_;
- double double_value_;
- std::chrono::system_clock::time_point time_value_;
-};
-
-class Lexer {
-public:
- explicit Lexer(std::istream& is) : is_(is), lineNo_(1) {}
-
- Token nextKeyToken();
- Token nextValueToken();
-
- int lineNo() const { return lineNo_; }
-
-private:
- bool current(char* c);
- void next();
- bool consume(char c);
-
- Token nextToken(bool isValueToken);
-
- void skipUntilNewLine();
-
- Token nextStringDoubleQuote();
- Token nextStringSingleQuote();
-
- Token nextKey();
- Token nextValue();
-
- Token parseAsTime(const std::string&);
-
- std::istream& is_;
- int lineNo_;
-};
-
-class Parser {
-public:
- explicit Parser(std::istream& is) : lexer_(is), token_(TokenType::ERROR) { nextKey(); }
-
- // Parses. If failed, value should be invalid value.
- // You can get the error by calling errorReason().
- Value parse();
- const std::string& errorReason();
-
-private:
- const Token& token() const { return token_; }
- void nextKey() { token_ = lexer_.nextKeyToken(); }
- void nextValue() { token_ = lexer_.nextValueToken(); }
-
- void skipForKey();
- void skipForValue();
-
- bool consumeForKey(TokenType);
- bool consumeForValue(TokenType);
- bool consumeEOLorEOFForKey();
-
- Value* parseGroupKey(Value* root);
-
- bool parseKeyValue(Value*);
- bool parseKey(std::string*);
- bool parseValue(Value*);
- bool parseBool(Value*);
- bool parseNumber(Value*);
- bool parseArray(Value*);
- bool parseInlineTable(Value*);
-
- void addError(const std::string& reason);
-
- Lexer lexer_;
- Token token_;
- std::string errorReason_;
-};
-
-} // namespace internal
-
-// ----------------------------------------------------------------------
-// Implementations
-
-inline ParseResult parse(std::istream& is)
-{
- internal::Parser parser(is);
- toml::Value v = parser.parse();
-
- if (v.valid())
- return ParseResult(std::move(v), std::string());
-
- return ParseResult(std::move(v), std::move(parser.errorReason()));
-}
-
-inline std::string format(std::stringstream& ss)
-{
- return ss.str();
-}
-
-template<typename T, typename... Args>
-std::string format(std::stringstream& ss, T&& t, Args&&... args)
-{
- ss << std::forward<T>(t);
- return format(ss, std::forward<Args>(args)...);
-}
-
-template<typename... Args>
-#if defined(_MSC_VER)
-__declspec(noreturn)
-#else
-[[noreturn]]
-#endif
-void failwith(Args&&... args)
-{
- std::stringstream ss;
- throw std::runtime_error(format(ss, std::forward<Args>(args)...));
-}
-
-namespace internal {
-
-inline std::string removeDelimiter(const std::string& s)
-{
- std::string r;
- for (char c : s) {
- if (c == '_')
- continue;
- r += c;
- }
- return r;
-}
-
-inline std::string unescape(const std::string& codepoint)
-{
- std::uint32_t x;
- std::uint8_t buf[8];
- std::stringstream ss(codepoint);
-
- ss >> std::hex >> x;
-
- if (x <= 0x7FUL) {
- // 0xxxxxxx
- buf[0] = 0x00 | ((x >> 0) & 0x7F);
- buf[1] = '\0';
- } else if (x <= 0x7FFUL) {
- // 110yyyyx 10xxxxxx
- buf[0] = 0xC0 | ((x >> 6) & 0xDF);
- buf[1] = 0x80 | ((x >> 0) & 0xBF);
- buf[2] = '\0';
- } else if (x <= 0xFFFFUL) {
- // 1110yyyy 10yxxxxx 10xxxxxx
- buf[0] = 0xE0 | ((x >> 12) & 0xEF);
- buf[1] = 0x80 | ((x >> 6) & 0xBF);
- buf[2] = 0x80 | ((x >> 0) & 0xBF);
- buf[3] = '\0';
- } else if (x <= 0x10FFFFUL) {
- // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
- buf[0] = 0xF0 | ((x >> 18) & 0xF7);
- buf[1] = 0x80 | ((x >> 12) & 0xBF);
- buf[2] = 0x80 | ((x >> 6) & 0xBF);
- buf[3] = 0x80 | ((x >> 0) & 0xBF);
- buf[4] = '\0';
- } else {
- buf[0] = '\0';
- }
-
- return reinterpret_cast<char*>(buf);
-}
-
-// Returns true if |s| is integer.
-// [+-]?\d+(_\d+)*
-inline bool isInteger(const std::string& s)
-{
- if (s.empty())
- return false;
-
- std::string::size_type p = 0;
- if (s[p] == '+' || s[p] == '-')
- ++p;
-
- while (p < s.size() && '0' <= s[p] && s[p] <= '9') {
- ++p;
- if (p < s.size() && s[p] == '_') {
- ++p;
- if (!(p < s.size() && '0' <= s[p] && s[p] <= '9'))
- return false;
- }
- }
-
- return p == s.size();
-}
-
-// Returns true if |s| is double.
-// [+-]? (\d+(_\d+)*)? (\.\d+(_\d+)*)? ([eE] [+-]? \d+(_\d+)*)?
-// 1----------- 2------------- 3----------------------
-// 2 or (1 and 3) should exist.
-inline bool isDouble(const std::string& s)
-{
- if (s.empty())
- return false;
-
- std::string::size_type p = 0;
- if (s[p] == '+' || s[p] == '-')
- ++p;
-
- bool ok = false;
- while (p < s.size() && '0' <= s[p] && s[p] <= '9') {
- ++p;
- ok = true;
-
- if (p < s.size() && s[p] == '_') {
- ++p;
- if (!(p < s.size() && '0' <= s[p] && s[p] <= '9'))
- return false;
- }
- }
-
- if (p < s.size() && s[p] == '.')
- ++p;
-
- while (p < s.size() && '0' <= s[p] && s[p] <= '9') {
- ++p;
- ok = true;
-
- if (p < s.size() && s[p] == '_') {
- ++p;
- if (!(p < s.size() && '0' <= s[p] && s[p] <= '9'))
- return false;
- }
- }
-
- if (!ok)
- return false;
-
- ok = false;
- if (p < s.size() && (s[p] == 'e' || s[p] == 'E')) {
- ++p;
- if (p < s.size() && (s[p] == '+' || s[p] == '-'))
- ++p;
- while (p < s.size() && '0' <= s[p] && s[p] <= '9') {
- ++p;
- ok = true;
-
- if (p < s.size() && s[p] == '_') {
- ++p;
- if (!(p < s.size() && '0' <= s[p] && s[p] <= '9'))
- return false;
- }
- }
- if (!ok)
- return false;
- }
-
- return p == s.size();
-}
-
-// static
-inline std::string escapeString(const std::string& s)
-{
- std::stringstream ss;
- for (size_t i = 0; i < s.size(); ++i) {
- switch (s[i]) {
- case '\n': ss << "\\n"; break;
- case '\r': ss << "\\r"; break;
- case '\t': ss << "\\t"; break;
- case '\"': ss << "\\\""; break;
- case '\'': ss << "\\\'"; break;
- case '\\': ss << "\\\\"; break;
- default: ss << s[i]; break;
- }
- }
-
- return ss.str();
-}
-
-} // namespace internal
-
-// ----------------------------------------------------------------------
-// Lexer
-
-namespace internal {
-
-inline bool Lexer::current(char* c)
-{
- int x = is_.peek();
- if (x == EOF)
- return false;
- *c = static_cast<char>(x);
- return true;
-}
-
-inline void Lexer::next()
-{
- int x = is_.get();
- if (x == '\n')
- ++lineNo_;
-}
-
-inline bool Lexer::consume(char c)
-{
- char x;
- if (!current(&x))
- return false;
- if (x != c)
- return false;
- next();
- return true;
-}
-
-inline void Lexer::skipUntilNewLine()
-{
- char c;
- while (current(&c)) {
- if (c == '\n')
- return;
- next();
- }
-}
-
-inline Token Lexer::nextStringDoubleQuote()
-{
- if (!consume('"'))
- return Token(TokenType::ERROR, std::string("string didn't start with '\"'"));
-
- std::string s;
- char c;
- bool multiline = false;
-
- if (current(&c) && c == '"') {
- next();
- if (!current(&c) || c != '"') {
- // OK. It's empty string.
- return Token(TokenType::STRING, std::string());
- }
-
- next();
- // raw string literal started.
- // Newline just after """ should be ignored.
- while (current(&c) && (c == ' ' || c == '\t'))
- next();
- if (current(&c) && c == '\n')
- next();
- multiline = true;
- }
-
- while (current(&c)) {
- next();
- if (c == '\\') {
- if (!current(&c))
- return Token(TokenType::ERROR, std::string("string has unknown escape sequence"));
- next();
- switch (c) {
- case 't': c = '\t'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 'u':
- case 'U': {
- int size = c == 'u' ? 4 : 8;
- std::string codepoint;
- for (int i = 0; i < size; ++i) {
- if (current(&c) && (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'))) {
- codepoint += c;
- next();
- } else {
- return Token(TokenType::ERROR, std::string("string has unknown escape sequence"));
- }
- }
- s += unescape(codepoint);
- continue;
- }
- case '"': c = '"'; break;
- case '\'': c = '\''; break;
- case '\\': c = '\\'; break;
- case '\n':
- while (current(&c) && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) {
- next();
- }
- continue;
- default:
- return Token(TokenType::ERROR, std::string("string has unknown escape sequence"));
- }
- } else if (c == '"') {
- if (multiline) {
- if (current(&c) && c == '"') {
- next();
- if (current(&c) && c == '"') {
- next();
- return Token(TokenType::MULTILINE_STRING, s);
- } else {
- s += '"';
- s += '"';
- continue;
- }
- } else {
- s += '"';
- continue;
- }
- } else {
- return Token(TokenType::STRING, s);
- }
- }
-
- s += c;
- }
-
- return Token(TokenType::ERROR, std::string("string didn't end"));
-}
-
-inline Token Lexer::nextStringSingleQuote()
-{
- if (!consume('\''))
- return Token(TokenType::ERROR, std::string("string didn't start with '\''?"));
-
- std::string s;
- char c;
-
- if (current(&c) && c == '\'') {
- next();
- if (!current(&c) || c != '\'') {
- // OK. It's empty string.
- return Token(TokenType::STRING, std::string());
- }
- next();
- // raw string literal started.
- // Newline just after """ should be ignored.
- if (current(&c) && c == '\n')
- next();
-
- while (current(&c)) {
- if (c == '\'') {
- next();
- if (current(&c) && c == '\'') {
- next();
- if (current(&c) && c == '\'') {
- next();
- return Token(TokenType::MULTILINE_STRING, s);
- } else {
- s += '\'';
- s += '\'';
- continue;
- }
- } else {
- s += '\'';
- continue;
- }
- }
-
- next();
- s += c;
- continue;
- }
-
- return Token(TokenType::ERROR, std::string("string didn't end with '\'\'\'' ?"));
- }
-
- while (current(&c)) {
- next();
- if (c == '\'') {
- return Token(TokenType::STRING, s);
- }
-
- s += c;
- }
-
- return Token(TokenType::ERROR, std::string("string didn't end with '\''?"));
-}
-
-inline Token Lexer::nextKey()
-{
- std::string s;
- char c;
- while (current(&c) && (isalnum(c) || c == '_' || c == '-')) {
- s += c;
- next();
- }
-
- if (s.empty())
- return Token(TokenType::ERROR, std::string("Unknown key format"));
-
- return Token(TokenType::IDENT, s);
-}
-
-inline Token Lexer::nextValue()
-{
- std::string s;
- char c;
-
- if (current(&c) && isalpha(c)) {
- s += c;
- next();
- while (current(&c) && isalpha(c)) {
- s += c;
- next();
- }
-
- if (s == "true")
- return Token(TokenType::BOOL, true);
- if (s == "false")
- return Token(TokenType::BOOL, false);
- return Token(TokenType::ERROR, std::string("Unknown ident: ") + s);
- }
-
- while (current(&c) && (('0' <= c && c <= '9') || c == '.' || c == 'e' || c == 'E' ||
- c == 'T' || c == 'Z' || c == '_' || c == ':' || c == '-' || c == '+')) {
- next();
- s += c;
- }
-
- if (isInteger(s)) {
- std::stringstream ss(removeDelimiter(s));
- std::int64_t x;
- ss >> x;
- return Token(TokenType::INT, x);
- }
-
- if (isDouble(s)) {
- std::stringstream ss(removeDelimiter(s));
- double d;
- ss >> d;
- return Token(TokenType::DOUBLE, d);
- }
-
- return parseAsTime(s);
-}
-
-inline Token Lexer::parseAsTime(const std::string& str)
-{
- const char* s = str.c_str();
-
- int n;
- int YYYY, MM, DD;
- if (sscanf(s, "%d-%d-%d%n", &YYYY, &MM, &DD, &n) != 3)
- return Token(TokenType::ERROR, std::string("Invalid token"));
-
- if (s[n] == '\0') {
- std::tm t;
- t.tm_sec = 0;
- t.tm_min = 0;
- t.tm_hour = 0;
- t.tm_mday = DD;
- t.tm_mon = MM - 1;
- t.tm_year = YYYY - 1900;
- auto tp = std::chrono::system_clock::from_time_t(timegm(&t));
- return Token(TokenType::TIME, tp);
- }
-
- if (s[n] != 'T')
- return Token(TokenType::ERROR, std::string("Invalid token"));
-
- s = s + n + 1;
-
- int hh, mm;
- double ss; // double for fraction
- if (sscanf(s, "%d:%d:%lf%n", &hh, &mm, &ss, &n) != 3)
- return Token(TokenType::ERROR, std::string("Invalid token"));
-
- std::tm t;
- t.tm_sec = static_cast<int>(ss);
- t.tm_min = mm;
- t.tm_hour = hh;
- t.tm_mday = DD;
- t.tm_mon = MM - 1;
- t.tm_year = YYYY - 1900;
- auto tp = std::chrono::system_clock::from_time_t(timegm(&t));
- ss -= static_cast<int>(ss);
- // TODO(mayah): workaround GCC 4.9.3 on cygwin does not have std::round, but round().
- tp += std::chrono::microseconds(static_cast<std::int64_t>(round(ss * 1000000)));
-
- if (s[n] == '\0')
- return Token(TokenType::TIME, tp);
-
- if (s[n] == 'Z' && s[n + 1] == '\0')
- return Token(TokenType::TIME, tp);
-
- s = s + n;
- // offset
- // [+/-]%d:%d
- char pn;
- int oh, om;
- if (sscanf(s, "%c%d:%d", &pn, &oh, &om) != 3)
- return Token(TokenType::ERROR, std::string("Invalid token"));
-
- if (pn != '+' && pn != '-')
- return Token(TokenType::ERROR, std::string("Invalid token"));
-
- if (pn == '+') {
- tp -= std::chrono::hours(oh);
- tp -= std::chrono::minutes(om);
- } else {
- tp += std::chrono::hours(oh);
- tp += std::chrono::minutes(om);
- }
-
- return Token(TokenType::TIME, tp);
-}
-
-inline Token Lexer::nextKeyToken()
-{
- return nextToken(false);
-}
-
-inline Token Lexer::nextValueToken()
-{
- return nextToken(true);
-}
-
-inline Token Lexer::nextToken(bool isValueToken)
-{
- char c;
- while (current(&c)) {
- if (c == ' ' || c == '\t' || c == '\r') {
- next();
- continue;
- }
-
- if (c == '#') {
- skipUntilNewLine();
- continue;
- }
-
- switch (c) {
- case '\n':
- next();
- return Token(TokenType::END_OF_LINE);
- case '=':
- next();
- return Token(TokenType::EQUAL);
- case '{':
- next();
- return Token(TokenType::LBRACE);
- case '}':
- next();
- return Token(TokenType::RBRACE);
- case '[':
- next();
- return Token(TokenType::LBRACKET);
- case ']':
- next();
- return Token(TokenType::RBRACKET);
- case ',':
- next();
- return Token(TokenType::COMMA);
- case '.':
- next();
- return Token(TokenType::DOT);
- case '\"':
- return nextStringDoubleQuote();
- case '\'':
- return nextStringSingleQuote();
- default:
- if (isValueToken) {
- return nextValue();
- } else {
- return nextKey();
- }
- }
- }
-
- return Token(TokenType::END_OF_FILE);
-}
-
-} // namespace internal
-
-// ----------------------------------------------------------------------
-
-// static
-inline const char* Value::typeToString(Value::Type type)
-{
- switch (type) {
- case NULL_TYPE: return "null";
- case BOOL_TYPE: return "bool";
- case INT_TYPE: return "int";
- case DOUBLE_TYPE: return "double";
- case STRING_TYPE: return "string";
- case TIME_TYPE: return "time";
- case ARRAY_TYPE: return "array";
- case TABLE_TYPE: return "table";
- default: return "unknown";
- }
-}
-
-inline Value::Value(const Value& v) :
- type_(v.type_)
-{
- switch (v.type_) {
- case NULL_TYPE: null_ = v.null_; break;
- case BOOL_TYPE: bool_ = v.bool_; break;
- case INT_TYPE: int_ = v.int_; break;
- case DOUBLE_TYPE: double_ = v.double_; break;
- case STRING_TYPE: string_ = new std::string(*v.string_); break;
- case TIME_TYPE: time_ = new Time(*v.time_); break;
- case ARRAY_TYPE: array_ = new Array(*v.array_); break;
- case TABLE_TYPE: table_ = new Table(*v.table_); break;
- default:
- assert(false);
- type_ = NULL_TYPE;
- null_ = nullptr;
- }
-}
-
-inline Value::Value(Value&& v) noexcept :
- type_(v.type_)
-{
- switch (v.type_) {
- case NULL_TYPE: null_ = v.null_; break;
- case BOOL_TYPE: bool_ = v.bool_; break;
- case INT_TYPE: int_ = v.int_; break;
- case DOUBLE_TYPE: double_ = v.double_; break;
- case STRING_TYPE: string_ = v.string_; break;
- case TIME_TYPE: time_ = v.time_; break;
- case ARRAY_TYPE: array_ = v.array_; break;
- case TABLE_TYPE: table_ = v.table_; break;
- default:
- assert(false);
- type_ = NULL_TYPE;
- null_ = nullptr;
- }
-
- v.type_ = NULL_TYPE;
- v.null_ = nullptr;
-}
-
-inline Value& Value::operator=(const Value& v)
-{
- if (this == &v)
- return *this;
-
- this->~Value();
-
- type_ = v.type_;
- switch (v.type_) {
- case NULL_TYPE: null_ = v.null_; break;
- case BOOL_TYPE: bool_ = v.bool_; break;
- case INT_TYPE: int_ = v.int_; break;
- case DOUBLE_TYPE: double_ = v.double_; break;
- case STRING_TYPE: string_ = new std::string(*v.string_); break;
- case TIME_TYPE: time_ = new Time(*v.time_); break;
- case ARRAY_TYPE: array_ = new Array(*v.array_); break;
- case TABLE_TYPE: table_ = new Table(*v.table_); break;
- default:
- assert(false);
- type_ = NULL_TYPE;
- null_ = nullptr;
- }
-
- return *this;
-}
-
-inline Value& Value::operator=(Value&& v) noexcept
-{
- if (this == &v)
- return *this;
-
- this->~Value();
-
- type_ = v.type_;
- switch (v.type_) {
- case NULL_TYPE: null_ = v.null_; break;
- case BOOL_TYPE: bool_ = v.bool_; break;
- case INT_TYPE: int_ = v.int_; break;
- case DOUBLE_TYPE: double_ = v.double_; break;
- case STRING_TYPE: string_ = v.string_; break;
- case TIME_TYPE: time_ = v.time_; break;
- case ARRAY_TYPE: array_ = v.array_; break;
- case TABLE_TYPE: table_ = v.table_; break;
- default:
- assert(false);
- type_ = NULL_TYPE;
- null_ = nullptr;
- }
-
- v.type_ = NULL_TYPE;
- v.null_ = nullptr;
- return *this;
-}
-
-inline Value::~Value()
-{
- switch (type_) {
- case STRING_TYPE:
- delete string_;
- break;
- case TIME_TYPE:
- delete time_;
- break;
- case ARRAY_TYPE:
- delete array_;
- break;
- case TABLE_TYPE:
- delete table_;
- break;
- default:
- break;
- }
-}
-
-inline size_t Value::size() const
-{
- switch (type_) {
- case NULL_TYPE:
- return 0;
- case ARRAY_TYPE:
- return array_->size();
- case TABLE_TYPE:
- return table_->size();
- default:
- return 1;
- }
-}
-
-inline bool Value::empty() const
-{
- return size() == 0;
-}
-
-template<> struct Value::ValueConverter<bool>
-{
- bool is(const Value& v) { return v.type() == Value::BOOL_TYPE; }
- bool to(const Value& v) { v.assureType<bool>(); return v.bool_; }
-
-};
-template<> struct Value::ValueConverter<int64_t>
-{
- bool is(const Value& v) { return v.type() == Value::INT_TYPE; }
- int64_t to(const Value& v) { v.assureType<int64_t>(); return v.int_; }
-};
-template<> struct Value::ValueConverter<int>
-{
- bool is(const Value& v) { return v.type() == Value::INT_TYPE; }
- int to(const Value& v) { v.assureType<int>(); return static_cast<int>(v.int_); }
-};
-template<> struct Value::ValueConverter<double>
-{
- bool is(const Value& v) { return v.type() == Value::DOUBLE_TYPE; }
- double to(const Value& v) { v.assureType<double>(); return v.double_; }
-};
-template<> struct Value::ValueConverter<std::string>
-{
- bool is(const Value& v) { return v.type() == Value::STRING_TYPE; }
- const std::string& to(const Value& v) { v.assureType<std::string>(); return *v.string_; }
-};
-template<> struct Value::ValueConverter<Time>
-{
- bool is(const Value& v) { return v.type() == Value::TIME_TYPE; }
- const Time& to(const Value& v) { v.assureType<Time>(); return *v.time_; }
-};
-template<> struct Value::ValueConverter<Array>
-{
- bool is(const Value& v) { return v.type() == Value::ARRAY_TYPE; }
- const Array& to(const Value& v) { v.assureType<Array>(); return *v.array_; }
-};
-template<> struct Value::ValueConverter<Table>
-{
- bool is(const Value& v) { return v.type() == Value::TABLE_TYPE; }
- const Table& to(const Value& v) { v.assureType<Table>(); return *v.table_; }
-};
-
-template<typename T>
-struct Value::ValueConverter<std::vector<T>>
-{
- bool is(const Value& v)
- {
- if (v.type() != Value::ARRAY_TYPE)
- return false;
- const Array& array = v.as<Array>();
- if (array.empty())
- return true;
- return array.front().is<T>();
- }
-
- std::vector<T> to(const Value& v)
- {
- const Array& array = v.as<Array>();
- if (array.empty())
- return std::vector<T>();
- array.front().assureType<T>();
-
- std::vector<T> result;
- for (const auto& element : array) {
- result.push_back(element.as<T>());
- }
-
- return result;
- }
-};
-
-namespace internal {
-template<typename T> inline const char* type_name();
-template<> inline const char* type_name<bool>() { return "bool"; }
-template<> inline const char* type_name<int>() { return "int"; }
-template<> inline const char* type_name<int64_t>() { return "int64_t"; }
-template<> inline const char* type_name<double>() { return "double"; }
-template<> inline const char* type_name<std::string>() { return "string"; }
-template<> inline const char* type_name<toml::Time>() { return "time"; }
-template<> inline const char* type_name<toml::Array>() { return "array"; }
-template<> inline const char* type_name<toml::Table>() { return "table"; }
-} // namespace internal
-
-template<typename T>
-inline void Value::assureType() const
-{
- if (!is<T>())
- failwith("type error: this value is ", typeToString(type_), " but ", internal::type_name<T>(), " was requested");
-}
-
-template<typename T>
-inline bool Value::is() const
-{
- return ValueConverter<T>().is(*this);
-}
-
-template<typename T>
-inline typename call_traits<T>::return_type Value::as() const
-{
- return ValueConverter<T>().to(*this);
-}
-
-inline bool Value::isNumber() const
-{
- return is<int>() || is<double>();
-}
-
-inline double Value::asNumber() const
-{
- if (is<int>())
- return as<int>();
- if (is<double>())
- return as<double>();
-
- failwith("type error: this value is ", typeToString(type_), " but number is requested");
-}
-
-inline std::time_t Value::as_time_t() const
-{
- return std::chrono::system_clock::to_time_t(as<Time>());
-}
-
-inline std::string Value::spaces(int num)
-{
- if (num <= 0)
- return std::string();
-
- return std::string(num, ' ');
-}
-
-inline std::string Value::escapeKey(const std::string& key)
-{
- auto position = std::find_if(key.begin(), key.end(), [](char c) -> bool {
- if (std::isalnum(c) || c == '_' || c == '-')
- return false;
- return true;
- });
-
- if (position != key.end()) {
- std::string escaped = "\"";
- for (const char& c : key) {
- if (c == '\\' || c == '"')
- escaped += '\\';
- escaped += c;
- }
- escaped += "\"";
-
- return escaped;
- }
-
- return key;
-}
-
-inline void Value::write(std::ostream* os, const std::string& keyPrefix, int indent) const
-{
- switch (type_) {
- case NULL_TYPE:
- failwith("null type value is not a valid value");
- break;
- case BOOL_TYPE:
- (*os) << (bool_ ? "true" : "false");
- break;
- case INT_TYPE:
- (*os) << int_;
- break;
- case DOUBLE_TYPE: {
- (*os) << std::fixed << std::showpoint << double_;
- break;
- }
- case STRING_TYPE:
- (*os) << '"' << internal::escapeString(*string_) << '"';
- break;
- case TIME_TYPE: {
- time_t tt = std::chrono::system_clock::to_time_t(*time_);
- std::tm t;
- gmtime_r(&tt, &t);
- char buf[256];
- sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
- (*os) << buf;
- break;
- }
- case ARRAY_TYPE:
- (*os) << '[';
- for (size_t i = 0; i < array_->size(); ++i) {
- if (i)
- (*os) << ", ";
- (*array_)[i].write(os, keyPrefix, -1);
- }
- (*os) << ']';
- break;
- case TABLE_TYPE:
- for (const auto& kv : *table_) {
- if (kv.second.is<Table>())
- continue;
- if (kv.second.is<Array>() && kv.second.size() > 0 && kv.second.find(0)->is<Table>())
- continue;
- (*os) << spaces(indent) << escapeKey(kv.first) << " = ";
- kv.second.write(os, keyPrefix, indent >= 0 ? indent + 1 : indent);
- (*os) << '\n';
- }
- for (const auto& kv : *table_) {
- if (kv.second.is<Table>()) {
- std::string key(keyPrefix);
- if (!keyPrefix.empty())
- key += ".";
- key += escapeKey(kv.first);
- (*os) << "\n" << spaces(indent) << "[" << key << "]\n";
- kv.second.write(os, key, indent >= 0 ? indent + 1 : indent);
- }
- if (kv.second.is<Array>() && kv.second.size() > 0 && kv.second.find(0)->is<Table>()) {
- std::string key(keyPrefix);
- if (!keyPrefix.empty())
- key += ".";
- key += escapeKey(kv.first);
- for (const auto& v : kv.second.as<Array>()) {
- (*os) << "\n" << spaces(indent) << "[[" << key << "]]\n";
- v.write(os, key, indent >= 0 ? indent + 1 : indent);
- }
- }
- }
- break;
- default:
- failwith("writing unknown type");
- break;
- }
-}
-
-inline void Value::writeFormatted(std::ostream* os, FormatFlag flags) const
-{
- int indent = flags & FORMAT_INDENT ? 0 : -1;
-
- write(os, std::string(), indent);
-}
-
-// static
-inline FormatFlag operator|(FormatFlag lhs, FormatFlag rhs)
-{
- return static_cast<FormatFlag>(static_cast<int>(lhs) | static_cast<int>(rhs));
-}
-
-// static
-inline std::ostream& operator<<(std::ostream& os, const toml::Value& v)
-{
- v.write(&os);
- return os;
-}
-
-// static
-inline bool operator==(const Value& lhs, const Value& rhs)
-{
- if (lhs.type() != rhs.type())
- return false;
-
- switch (lhs.type()) {
- case Value::Type::NULL_TYPE:
- return true;
- case Value::Type::BOOL_TYPE:
- return lhs.bool_ == rhs.bool_;
- case Value::Type::INT_TYPE:
- return lhs.int_ == rhs.int_;
- case Value::Type::DOUBLE_TYPE:
- return lhs.double_ == rhs.double_;
- case Value::Type::STRING_TYPE:
- return *lhs.string_ == *rhs.string_;
- case Value::Type::TIME_TYPE:
- return *lhs.time_ == *rhs.time_;
- case Value::Type::ARRAY_TYPE:
- return *lhs.array_ == *rhs.array_;
- case Value::Type::TABLE_TYPE:
- return *lhs.table_ == *rhs.table_;
- default:
- failwith("unknown type");
- }
-}
-
-template<typename T>
-inline typename call_traits<T>::return_type Value::get(const std::string& key) const
-{
- if (!is<Table>())
- failwith("type must be table to do get(key).");
-
- const Value* obj = find(key);
- if (!obj)
- failwith("key ", key, " was not found.");
-
- return obj->as<T>();
-}
-
-inline const Value* Value::find(const std::string& key) const
-{
- if (!is<Table>())
- return nullptr;
-
- std::istringstream ss(key);
- internal::Lexer lexer(ss);
-
- const Value* current = this;
- while (true) {
- internal::Token t = lexer.nextKeyToken();
- if (!(t.type() == internal::TokenType::IDENT || t.type() == internal::TokenType::STRING))
- return nullptr;
-
- std::string part = t.strValue();
- t = lexer.nextKeyToken();
- if (t.type() == internal::TokenType::DOT) {
- current = current->findChild(part);
- if (!current || !current->is<Table>())
- return nullptr;
- } else if (t.type() == internal::TokenType::END_OF_FILE) {
- return current->findChild(part);
- } else {
- return nullptr;
- }
- }
-}
-
-inline Value* Value::find(const std::string& key)
-{
- return const_cast<Value*>(const_cast<const Value*>(this)->find(key));
-}
-
-inline bool Value::merge(const toml::Value& v)
-{
- if (this == &v)
- return true;
- if (!is<Table>() || !v.is<Table>())
- return false;
-
- for (const auto& kv : *v.table_) {
- if (Value* tmp = find(kv.first)) {
- // If both are table, we merge them.
- if (tmp->is<Table>() && kv.second.is<Table>()) {
- if (!tmp->merge(kv.second))
- return false;
- } else {
- setChild(kv.first, kv.second);
- }
- } else {
- setChild(kv.first, kv.second);
- }
- }
-
- return true;
-}
-
-inline Value* Value::set(const std::string& key, const Value& v)
-{
- Value* result = ensureValue(key);
- *result = v;
- return result;
-}
-
-inline Value* Value::setChild(const std::string& key, const Value& v)
-{
- if (!valid())
- *this = Value((Table()));
-
- if (!is<Table>())
- failwith("type must be table to do set(key, v).");
-
- (*table_)[key] = v;
- return &(*table_)[key];
-}
-
-inline Value* Value::setChild(const std::string& key, Value&& v)
-{
- if (!valid())
- *this = Value((Table()));
-
- if (!is<Table>())
- failwith("type must be table to do set(key, v).");
-
- (*table_)[key] = std::move(v);
- return &(*table_)[key];
-}
-
-inline bool Value::erase(const std::string& key)
-{
- if (!is<Table>())
- return false;
-
- std::istringstream ss(key);
- internal::Lexer lexer(ss);
-
- Value* current = this;
- while (true) {
- internal::Token t = lexer.nextKeyToken();
- if (!(t.type() == internal::TokenType::IDENT || t.type() == internal::TokenType::STRING))
- return false;
-
- std::string part = t.strValue();
- t = lexer.nextKeyToken();
- if (t.type() == internal::TokenType::DOT) {
- current = current->findChild(part);
- if (!current || !current->is<Table>())
- return false;
- } else if (t.type() == internal::TokenType::END_OF_FILE) {
- return current->eraseChild(part);
- } else {
- return false;
- }
- }
-}
-
-inline bool Value::eraseChild(const std::string& key)
-{
- if (!is<Table>())
- failwith("type must be table to do erase(key).");
-
- return table_->erase(key) > 0;
-}
-
-inline Value& Value::operator[](const std::string& key)
-{
- if (!valid())
- *this = Value((Table()));
-
- if (Value* v = findChild(key))
- return *v;
-
- return *setChild(key, Value());
-}
-
-template<typename T>
-inline typename call_traits<T>::return_type Value::get(size_t index) const
-{
- if (!is<Array>())
- failwith("type must be array to do get(index).");
-
- if (array_->size() <= index)
- failwith("index out of bound");
-
- return (*array_)[index].as<T>();
-}
-
-inline const Value* Value::find(size_t index) const
-{
- if (!is<Array>())
- return nullptr;
- if (index < array_->size())
- return &(*array_)[index];
- return nullptr;
-}
-
-inline Value* Value::find(size_t index)
-{
- return const_cast<Value*>(const_cast<const Value*>(this)->find(index));
-}
-
-inline Value* Value::push(const Value& v)
-{
- if (!valid())
- *this = Value((Array()));
- else if (!is<Array>())
- failwith("type must be array to do push(Value).");
-
- array_->push_back(v);
- return &array_->back();
-}
-
-inline Value* Value::push(Value&& v)
-{
- if (!valid())
- *this = Value((Array()));
- else if (!is<Array>())
- failwith("type must be array to do push(Value).");
-
- array_->push_back(std::move(v));
- return &array_->back();
-}
-
-inline Value* Value::ensureValue(const std::string& key)
-{
- if (!valid())
- *this = Value((Table()));
- if (!is<Table>()) {
- failwith("encountered non table value");
- }
-
- std::istringstream ss(key);
- internal::Lexer lexer(ss);
-
- Value* current = this;
- while (true) {
- internal::Token t = lexer.nextKeyToken();
- if (!(t.type() == internal::TokenType::IDENT || t.type() == internal::TokenType::STRING)) {
- failwith("invalid key");
- }
-
- std::string part = t.strValue();
- t = lexer.nextKeyToken();
- if (t.type() == internal::TokenType::DOT) {
- if (Value* candidate = current->findChild(part)) {
- if (!candidate->is<Table>())
- failwith("encountered non table value");
-
- current = candidate;
- } else {
- current = current->setChild(part, Table());
- }
- } else if (t.type() == internal::TokenType::END_OF_FILE) {
- if (Value* v = current->findChild(part))
- return v;
- return current->setChild(part, Value());
- } else {
- failwith("invalid key");
- }
- }
-}
-
-inline Value* Value::findChild(const std::string& key)
-{
- assert(is<Table>());
-
- auto it = table_->find(key);
- if (it == table_->end())
- return nullptr;
-
- return &it->second;
-}
-
-inline const Value* Value::findChild(const std::string& key) const
-{
- assert(is<Table>());
-
- auto it = table_->find(key);
- if (it == table_->end())
- return nullptr;
-
- return &it->second;
-}
-
-// ----------------------------------------------------------------------
-
-namespace internal {
-
-inline void Parser::skipForKey()
-{
- while (token().type() == TokenType::END_OF_LINE)
- nextKey();
-}
-
-inline void Parser::skipForValue()
-{
- while (token().type() == TokenType::END_OF_LINE)
- nextValue();
-}
-
-inline bool Parser::consumeForKey(TokenType type)
-{
- if (token().type() == type) {
- nextKey();
- return true;
- }
-
- return false;
-}
-
-inline bool Parser::consumeForValue(TokenType type)
-{
- if (token().type() == type) {
- nextValue();
- return true;
- }
-
- return false;
-}
-
-inline bool Parser::consumeEOLorEOFForKey()
-{
- if (token().type() == TokenType::END_OF_LINE || token().type() == TokenType::END_OF_FILE) {
- nextKey();
- return true;
- }
-
- return false;
-}
-
-inline void Parser::addError(const std::string& reason)
-{
- if (!errorReason_.empty())
- return;
-
- std::stringstream ss;
- ss << "Error: line " << lexer_.lineNo() << ": " << reason;
- errorReason_ = ss.str();
-}
-
-inline const std::string& Parser::errorReason()
-{
- return errorReason_;
-}
-
-inline Value Parser::parse()
-{
- Value root((Table()));
- Value* currentValue = &root;
-
- while (true) {
- skipForKey();
- if (token().type() == TokenType::END_OF_FILE)
- break;
- if (token().type() == TokenType::LBRACKET) {
- currentValue = parseGroupKey(&root);
- if (!currentValue) {
- addError("error when parsing group key");
- return Value();
- }
- continue;
- }
-
- if (!parseKeyValue(currentValue)) {
- addError("error when parsing key Value");
- return Value();
- }
- }
- return root;
-}
-
-inline Value* Parser::parseGroupKey(Value* root)
-{
- if (!consumeForKey(TokenType::LBRACKET))
- return nullptr;
-
- bool isArray = false;
- if (token().type() == TokenType::LBRACKET) {
- nextKey();
- isArray = true;
- }
-
- Value* currentValue = root;
- while (true) {
- if (token().type() != TokenType::IDENT && token().type() != TokenType::STRING)
- return nullptr;
-
- std::string key = token().strValue();
- nextKey();
-
- if (token().type() == TokenType::DOT) {
- nextKey();
- if (Value* candidate = currentValue->findChild(key)) {
- if (candidate->is<Array>() && candidate->size() > 0)
- candidate = candidate->find(candidate->size() - 1);
- if (!candidate->is<Table>())
- return nullptr;
- currentValue = candidate;
- } else {
- currentValue = currentValue->setChild(key, Table());
- }
- continue;
- }
-
- if (token().type() == TokenType::RBRACKET) {
- nextKey();
- if (Value* candidate = currentValue->findChild(key)) {
- if (isArray) {
- if (!candidate->is<Array>())
- return nullptr;
- currentValue = candidate->push(Table());
- } else {
- if (candidate->is<Array>() && candidate->size() > 0)
- candidate = candidate->find(candidate->size() - 1);
- if (!candidate->is<Table>())
- return nullptr;
- currentValue = candidate;
- }
- } else {
- if (isArray) {
- currentValue = currentValue->setChild(key, Array());
- currentValue = currentValue->push(Table());
- } else {
- currentValue = currentValue->setChild(key, Table());
- }
- }
- break;
- }
-
- return nullptr;
- }
-
- if (isArray) {
- if (!consumeForKey(TokenType::RBRACKET))
- return nullptr;
- }
-
- if (!consumeEOLorEOFForKey())
- return nullptr;
-
- return currentValue;
-}
-
-inline bool Parser::parseKeyValue(Value* current)
-{
- std::string key;
- if (!parseKey(&key)) {
- addError("parse key failed");
- return false;
- }
- if (!consumeForValue(TokenType::EQUAL)) {
- addError("no equal?");
- return false;
- }
-
- Value v;
- if (!parseValue(&v))
- return false;
- if (!consumeEOLorEOFForKey())
- return false;
-
- if (current->has(key)) {
- addError("Multiple same key: " + key);
- return false;
- }
-
- current->setChild(key, std::move(v));
- return true;
-}
-
-inline bool Parser::parseKey(std::string* key)
-{
- key->clear();
-
- if (token().type() == TokenType::IDENT || token().type() == TokenType::STRING) {
- *key = token().strValue();
- nextValue();
- return true;
- }
-
- return false;
-}
-
-inline bool Parser::parseValue(Value* v)
-{
- switch (token().type()) {
- case TokenType::STRING:
- case TokenType::MULTILINE_STRING:
- *v = token().strValue();
- nextValue();
- return true;
- case TokenType::LBRACKET:
- return parseArray(v);
- case TokenType::LBRACE:
- return parseInlineTable(v);
- case TokenType::BOOL:
- *v = token().boolValue();
- nextValue();
- return true;
- case TokenType::INT:
- *v = token().intValue();
- nextValue();
- return true;
- case TokenType::DOUBLE:
- *v = token().doubleValue();
- nextValue();
- return true;
- case TokenType::TIME:
- *v = token().timeValue();
- nextValue();
- return true;
- case TokenType::ERROR:
- addError(token().strValue());
- return false;
- default:
- addError("unexpected token");
- return false;
- }
-}
-
-inline bool Parser::parseBool(Value* v)
-{
- if (token().strValue() == "true") {
- nextValue();
- *v = true;
- return true;
- }
-
- if (token().strValue() == "false") {
- nextValue();
- *v = false;
- return true;
- }
-
- return false;
-}
-
-inline bool Parser::parseArray(Value* v)
-{
- if (!consumeForValue(TokenType::LBRACKET))
- return false;
-
- Array a;
- while (true) {
- skipForValue();
-
- if (token().type() == TokenType::RBRACKET)
- break;
-
- skipForValue();
- Value x;
- if (!parseValue(&x))
- return false;
-
- if (!a.empty()) {
- if (a.front().type() != x.type()) {
- addError("type check failed");
- return false;
- }
- }
-
- a.push_back(std::move(x));
- skipForValue();
- if (token().type() == TokenType::RBRACKET)
- break;
- if (token().type() == TokenType::COMMA)
- nextValue();
- }
-
- if (!consumeForValue(TokenType::RBRACKET))
- return false;
- *v = std::move(a);
- return true;
-}
-
-inline bool Parser::parseInlineTable(Value* value)
-{
- // For inline table, next is KEY, so use consumeForKey here.
- if (!consumeForKey(TokenType::LBRACE))
- return false;
-
- Value t((Table()));
- bool first = true;
- while (true) {
- if (token().type() == TokenType::RBRACE) {
- break;
- }
-
- if (!first) {
- if (token().type() != TokenType::COMMA) {
- addError("inline table didn't have ',' for delimiter?");
- return false;
- }
- nextKey();
- }
- first = false;
-
- std::string key;
- if (!parseKey(&key))
- return false;
- if (!consumeForValue(TokenType::EQUAL))
- return false;
- Value v;
- if (!parseValue(&v))
- return false;
-
- if (t.has(key)) {
- addError("inline table has multiple same keys: key=" + key);
- return false;
- }
-
- t.set(key, v);
- }
-
- if (!consumeForValue(TokenType::RBRACE))
- return false;
- *value = std::move(t);
- return true;
-}
-
-} // namespace internal
-} // namespace toml
-
-#endif // TINYTOML_H_
diff --git a/src/browser.cpp b/src/browser.cpp
index 14fee3e..60b8810 100644
--- a/src/browser.cpp
+++ b/src/browser.cpp
@@ -21,16 +21,14 @@
#include "browser.h"
#include "mainwindow.h"
#include <QtWebEngine>
-#include <QMessageBox>
#include <QDir>
-#include <QPluginLoader>
-#include "interfaces.h"
Browser::Browser(int &argc, char *argv[]) :
SingleApplication(argc, argv)
{
setApplicationName("smolbote");
+ setWindowIcon(QIcon(":/icon.svg"));
#ifdef GIT_VERSION
setApplicationVersion(GIT_VERSION);
#else
@@ -40,95 +38,58 @@ Browser::Browser(int &argc, char *argv[]) :
Browser::~Browser()
{
- qDeleteAll(m_windows);
- m_windows.clear();
+// qDeleteAll(m_windows);
+// m_windows.clear();
}
-QString Browser::applicationLongVersion() const
+void Browser::setConfiguration(std::shared_ptr<Configuration> &config)
{
-#ifdef GIT_DESCRIBE
- return QString(GIT_DESCRIBE);
-#else
- return applicationVersion();
-#endif
+ m_config = config;
+
+// m_bookmarksManager = std::make_shared<BookmarksWidget>(QString::fromStdString(m_config->value<std::string>("bookmarks.path").value()));
+// m_downloadManager = std::make_shared<DownloadsWidget>(QString::fromStdString(m_config->value<std::string>("downloads.path").value()));
}
-void Browser::loadPlugins()
+void Browser::loadProfiles()
{
- // Loading plugins
- qDebug(">> Looking for plugins...");
+ Q_ASSERT(m_config);
- // Look for plugins in "../lib/smolbote/plugins"
- QDir dir = QDir::current();
- dir.cd("../lib/smolbote/plugins");
+ const QString &path = QString::fromStdString(m_config->value<std::string>("profile.path").value());
- // Load all plugins
- const QStringList files = dir.entryList(QDir::Files | QDir::Readable);
- for(const QString &filename : files) {
- qDebug("Loading %s", qUtf8Printable(filename));
+#ifdef QT_DEBUG
+ qDebug(">> Looking for profiles... [%s]", qUtf8Printable(path));
+#endif
- QPluginLoader loader(dir.absoluteFilePath(filename));
- QObject *plugin = loader.instance();
- if(plugin) {
- PluginInterface *p = qobject_cast<PluginInterface *>(plugin);
- if(p) {
- qDebug("Successfully loaded plugin [name = %s]", qUtf8Printable(p->name()));
- m_plugin = plugin;
- }
- } else {
- qDebug("Plugin load failed");
- }
- }
+ // Build a profile list from the folders in the profile.path
+ QDir profileDir(path);
+ const QStringList profileList = profileDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
- qDebug("<< Plugins end...");
-}
-
-void Browser::loadProfiles()
-{
- qDebug(">> Looking for profiles...");
- profile("");
- QDir dir(settings()->value("browser.profile.path").toString());
- const QStringList profileList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
for(const QString &name : profileList) {
- qDebug("- Adding profile %s", qUtf8Printable(name));
- profile(name);
+ m_profiles.insert(name, new WebEngineProfile(name, profileDir.absoluteFilePath(name), this));
}
- qDebug("<< Profiles end...");
- //connect(this, SIGNAL(messageAvailable(QStringList)), this, SLOT(addWindow(QStringList)));
- connect(this, &Browser::messageAvailable, this, [&](const QHash<QString, QVariant> params) {
+ // Also add the Off-the-record profile
+ m_profiles.insert("", new WebEngineProfile(this));
- //qDebug("Creating new window for [%s]", qUtf8Printable(params["urls"].toString()));
+ // set default profile
+ m_defaultProfile = m_profiles[QString::fromStdString(m_config->value<std::string>("browser.profile").value())];
- createWindow(params);
- });
-}
-
-Browser *Browser::instance()
-{
- return static_cast<Browser *>(QCoreApplication::instance());
-}
-
-Settings *Browser::settings()
-{
- Q_ASSERT(m_settings);
- return m_settings.get();
+#ifdef QT_DEBUG
+ qDebug("<< Profiles end...");
+#endif
}
-BookmarksWidget *Browser::bookmarks()
+/*
+std::shared_ptr<BookmarksWidget> &Browser::bookmarks()
{
- if(!m_bookmarksManager) {
- m_bookmarksManager = QSharedPointer<BookmarksWidget>(new BookmarksWidget(settings()->value("bookmarks.path").toString()), &QObject::deleteLater);
- }
- return m_bookmarksManager.data();
+ Q_ASSERT(m_bookmarksManager);
+ return m_bookmarksManager;
}
-DownloadsWidget *Browser::downloads()
+std::shared_ptr<DownloadsWidget> &Browser::downloads()
{
- if(!m_downloadManager) {
- m_downloadManager = QSharedPointer<DownloadsWidget>(new DownloadsWidget(settings()->value("downloads.path").toString()), &QObject::deleteLater);
- }
- return m_downloadManager.data();
+ Q_ASSERT(m_downloadManager);
+ return m_downloadManager;
}
BlockerManager *Browser::blocklists()
@@ -139,52 +100,6 @@ BlockerManager *Browser::blocklists()
return m_blocklistManager;
}
-void Browser::loadSettings(const QString &path)
-{
- QString configLocation, defaultsLocation;
-
- // set custom config path if any
- if(!path.isEmpty()) {
- configLocation = path;
-
- } else {
- // no custom config has been set
- // check if config file exists for this user
- QString cpath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/poi.conf";
- if(QFile::exists(cpath)) {
- configLocation = cpath;
- }
- // else there is no user overrides
- }
-
- // set defaults location
- // check system-specific locations
-#ifdef Q_OS_LINUX
- if(QFile::exists("/usr/share/smolbote/poi.conf")) {
- defaultsLocation = "/usr/share/smolbote/poi.conf";
- } else if(QFile::exists("/usr/local/share/smolbote/poi.conf")) {
- defaultsLocation = "/usr/local/share/smolbote/poi.conf";
- }
-#endif
-
- // if no default config is found, then use the built-in one
- if(defaultsLocation.isEmpty()) {
- defaultsLocation = ":/poi.toml";
- }
-
- m_settings = std::unique_ptr<Settings>(new Settings(configLocation, defaultsLocation));
-
-#ifdef QT_DEBUG
- if(m_settings->isEmpty()) {
- // There are no keys in the settings
- QMessageBox::information(0,
- tr("Configuration is empty"),
- tr("The configuration file <i>%1</i> is empty.<br>"
- "Using default values from <i>%2</i>.").arg(configLocation, defaultsLocation));
- }
-#endif
-}
-
MainWindow *Browser::activeWindow()
{
if(m_windows.empty()) {
@@ -197,73 +112,30 @@ MainWindow *Browser::activeWindow()
}
}
return m_windows.first().data();
-}
+}*/
-MainWindow *Browser::createWindow(const QHash<QString, QVariant> options)
+MainWindow *Browser::createWindow()
{
- Q_ASSERT(options.contains("urls"));
+ // the window will delete itself when it closes, so we don't need to delete it
+ MainWindow *window = new MainWindow(m_config);
+ window->setProfile(m_defaultProfile);
- MainWindow *w = new MainWindow();
+ m_windows.append(window);
- m_windows.append(QPointer<MainWindow>(w));
- connect(w, &MainWindow::destroyed, this, [&]() {
- clean();
+ // has to be window.get(), but can't be *window
+ connect(window, &MainWindow::destroyed, this, [this, window]() {
+ m_windows.removeOne(window);
});
+ window->show();
- QString profileName;
- if(options.contains("profile")) {
- profileName = options.value("profile").toString();
- }
- const QStringList urls = options.value("urls").toStringList();
- if(urls.isEmpty()) {
- w->newTab(profile(profileName)->homepage());
- } else {
- for(const QString url : urls) {
- w->newTab(QUrl::fromUserInput(url));
- }
- }
-
- w->show();
-
- return w;
-}
-
-void Browser::clean()
-{
- for(int i = m_windows.count() - 1; i >= 0; i--) {
- if(m_windows[i].isNull()) {
- m_windows.removeAt(i);
-#ifdef QT_DEBUG
- qDebug("Removed deleted window from window list");
-#endif
- }
- }
+ return window;
}
WebEngineProfile* Browser::profile(const QString name)
{
- if(!m_profiles.contains(name)) {
- if(name.isEmpty()) {
- // Create off-the-record profile
- m_profiles.insert(name, new WebEngineProfile(this));
- } else {
- // Create regular profile
- m_profiles.insert(name, new WebEngineProfile(name, this));
- }
-
- if(!m_urlRequestInterceptor) {
- m_urlRequestInterceptor = new UrlRequestInterceptor(this);
- m_urlRequestInterceptor->setSubscription(blocklists());
- }
-
- m_profiles[name]->setRequestInterceptor(m_urlRequestInterceptor);
-
- connect(m_profiles[name], SIGNAL(downloadRequested(QWebEngineDownloadItem*)), downloads(), SLOT(addDownload(QWebEngineDownloadItem*)));
- }
-
return m_profiles[name];
}
-
+/*
QStringList Browser::profiles()
{
QStringList l;
@@ -273,8 +145,4 @@ QStringList Browser::profiles()
}
return l;
}
-
-QObject *Browser::plugin(const QString name)
-{
- return m_plugin;
-}
+*/
diff --git a/src/browser.h b/src/browser.h
index dedb933..ee9e917 100644
--- a/src/browser.h
+++ b/src/browser.h
@@ -22,21 +22,16 @@
#define BROWSER_H
#include "singleapplication.h"
-#include <bookmarks/bookmarkswidget.h>
-#include <downloads/downloadswidget.h>
-#include "settings.h"
+//#include <bookmarks/bookmarkswidget.h>
+//#include <downloads/downloadswidget.h>
#include "webengine/webengineprofile.h"
-#include "filter/blockermanager.h"
-#include "webengine/urlinterceptor.h"
+//#include "filter/blockermanager.h"
+//#include "webengine/urlinterceptor.h"
+#include <QVector>
#include <memory>
-#include <QSharedPointer>
-
-#ifdef browser
-#undef browser
-#endif
-#define browser Browser::instance()
+#include "settings/configuration.h"
class MainWindow;
class Browser : public SingleApplication
@@ -47,45 +42,35 @@ public:
explicit Browser(int &argc, char *argv[]);
~Browser();
- QString applicationLongVersion() const;
+ void setConfiguration(std::shared_ptr<Configuration> &config);
- void loadSettings(const QString &path);
- void loadPlugins();
void loadProfiles();
-
- static Browser *instance();
-
- Settings *settings();
- BookmarksWidget *bookmarks();
- DownloadsWidget *downloads();
- BlockerManager *blocklists();
-
- MainWindow *activeWindow();
-
WebEngineProfile *profile(const QString name);
- QStringList profiles();
+ // QStringList profiles();
+
+// std::shared_ptr<BookmarksWidget>& bookmarks();
+// std::shared_ptr<DownloadsWidget>& downloads();
+// BlockerManager *blocklists();
- QObject *plugin(const QString name);
- QStringList plugins();
+ //MainWindow *activeWindow();
public slots:
- MainWindow* createWindow(const QHash<QString, QVariant> options);
- void clean();
+ MainWindow* createWindow();
private:
Q_DISABLE_COPY(Browser)
- std::unique_ptr<Settings> m_settings;
+ std::shared_ptr<Configuration> m_config;
- QVector<QPointer<MainWindow>> m_windows;
+ QVector<MainWindow *> m_windows;
+// QVector<QPointer<MainWindow>> m_windows;
QHash<QString, WebEngineProfile *> m_profiles;
+ WebEngineProfile* m_defaultProfile;
- UrlRequestInterceptor *m_urlRequestInterceptor = nullptr;
- QSharedPointer<BookmarksWidget> m_bookmarksManager;
- QSharedPointer<DownloadsWidget> m_downloadManager;
- BlockerManager *m_blocklistManager = nullptr;
-
- QObject *m_plugin = nullptr;
+// UrlRequestInterceptor *m_urlRequestInterceptor = nullptr;
+// std::shared_ptr<BookmarksWidget> m_bookmarksManager;
+// std::shared_ptr<DownloadsWidget> m_downloadManager;
+// BlockerManager *m_blocklistManager = nullptr;
};
diff --git a/src/forms/aboutdialog.cpp b/src/forms/aboutdialog.cpp
index e9c2a93..addf66c 100644
--- a/src/forms/aboutdialog.cpp
+++ b/src/forms/aboutdialog.cpp
@@ -20,7 +20,6 @@
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
-#include "browser.h"
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent),
@@ -34,42 +33,51 @@ AboutDialog::AboutDialog(QWidget *parent) :
QLabel *aboutLabel = new QLabel(this);
aboutLabel->setWordWrap(true);
aboutLabel->setText(tr("<h2>smolbote %1</h2>"
- "<p><i>yet another Qute browser</i></p>"
- "<p>Copyright (C) 2017 Xian Nox</p>"
- "<p>This program comes with ABSOLUTELY NO WARRANTY. "
- "This is free software, and you are welcome to redistribute it under the conditions set by the GNU GPLv3.</p>")
+ "<p><i>yet another Qute browser</i></p>")
.arg(qApp->applicationVersion()));
ui->toolBox->addItem(aboutLabel, tr("About"));
- QLabel *detailsLabel = new QLabel(this);
- detailsLabel->setWordWrap(true);
- detailsLabel->setText(tr("<h3>Version %1</h3>"
- "<p>"
- "Based on Qt " QT_VERSION_STR "<br>"
-#if defined __clang__
- "Compiled with Clang " __clang_version__ "<br>"
-#elif defined __GNUC__
- "Compiled with GCC " __VERSION__ "<br>"
-#endif
- "Configuration lives in %2<br>"
- "Default configuration lives in %3"
- "</p>")
- .arg(browser->applicationLongVersion(),
- browser->settings()->configurationPath(),
- browser->settings()->defaultsPath()));
- ui->toolBox->addItem(detailsLabel, tr("Details"));
+ QLabel *licenseLabel = new QLabel(this);
+ licenseLabel->setWordWrap(true);
+ licenseLabel->setText(tr("<p>Copyright (C) 2017 Xian Nox</p>"
+ "<p>This program is free software, and you are welcome to use it under the conditions set by the GNU GPLv3:"
+ "<ul>"
+ "<li> the freedom to use the software for any purpose,</li>"
+ "<li> the freedom to change the software to suit your needs,</li>"
+ "<li> the freedom to share the software with anyone,</li>"
+ "<li> the freedom to share the changes you make, and</li>"
+ "<li> the responsibility to grant the same freedoms when sharing the software.</li>"
+ "</ul>"
+ "<p>You can find the full license text in LICENSE.md.</p>"));
+ ui->toolBox->addItem(licenseLabel, tr("License"));
QLabel *libsLabel = new QLabel(this);
libsLabel->setWordWrap(true);
- libsLabel->setText(tr("<ul>"
- "<li>Qt %1</li>"
- "<li>tinytoml</li>"
- "</ul>")
- .arg(qVersion()));
- ui->toolBox->addItem(libsLabel, tr("Libraries"));
+ libsLabel->setText(tr("<h3>Version %1</h3>"
+ "<p>"
+ "Based on Qt " QT_VERSION_STR "<br>"
+ "Compiled with %2"
+ "</p>"
+ "<p><ul>"
+ "<li>Qt %3</li>"
+ "<li>libconfig</li>"
+ "</ul></p>")
+ .arg(qApp->applicationVersion(), getCompiler(), qVersion()));
+ ui->toolBox->addItem(libsLabel, tr("Details"));
}
AboutDialog::~AboutDialog()
{
delete ui;
}
+
+constexpr const char *getCompiler()
+{
+ if(__clang__) {
+ return "Clang " __clang_version__;
+ } else if(__GNUC__) {
+ return "GCC " __VERSION__;
+ } else {
+ return "unknown compiler";
+ }
+}
diff --git a/src/forms/aboutdialog.h b/src/forms/aboutdialog.h
index 98a4a49..e7b2bb3 100644
--- a/src/forms/aboutdialog.h
+++ b/src/forms/aboutdialog.h
@@ -32,11 +32,13 @@ class AboutDialog : public QDialog
Q_OBJECT
public:
- explicit AboutDialog(QWidget *parent = 0);
+ explicit AboutDialog(QWidget *parent = nullptr);
~AboutDialog();
private:
Ui::AboutDialog *ui;
};
+constexpr const char* getCompiler();
+
#endif // ABOUTDIALOG_H
diff --git a/src/forms/profilesdialog.cpp b/src/forms/profilesdialog.cpp
index 7723683..b295675 100644
--- a/src/forms/profilesdialog.cpp
+++ b/src/forms/profilesdialog.cpp
@@ -36,7 +36,7 @@ ProfilesDialog::ProfilesDialog(MainWindow *window, QWidget *parent) :
{
m_window = window;
- m_view = new ProfileView(0, this);
+ m_view = new ProfileView(nullptr, this);
// Hide the profile view because we're fancy
// Give focus to the top widget because otherwise the listwidget gains focus
@@ -69,10 +69,10 @@ void ProfilesDialog::loadProfiles()
{
ui->listWidget->clear();
- for(QString name : browser->profiles()) {
- QListWidgetItem *item = new QListWidgetItem(browser->profile(name)->name(), ui->listWidget);
- item->setData(Qt::UserRole, name);
- }
+// for(QString name : browser->profiles()) {
+// QListWidgetItem *item = new QListWidgetItem(browser->profile(name)->name(), ui->listWidget);
+// item->setData(Qt::UserRole, name);
+// }
}
void ProfilesDialog::newProfile()
@@ -80,19 +80,19 @@ void ProfilesDialog::newProfile()
bool ok;
QString name = QInputDialog::getText(this, tr("Profile Name"), tr("Profile Name:"), QLineEdit::Normal, tr("Default"), &ok);
- if(ok) {
- browser->profile(name);
- loadProfiles();
- }
+// if(ok) {
+// browser->profile(name);
+// loadProfiles();
+// }
}
void ProfilesDialog::loadSelectedProfile()
{
- m_window->setProfile(browser->profile(ui->listWidget->currentItem()->data(Qt::UserRole).toString()));
+ //m_window->setProfile(browser->profile(ui->listWidget->currentItem()->data(Qt::UserRole).toString()));
}
void ProfilesDialog::viewProfile(int index)
{
- m_view->setProfile(browser->profile(ui->listWidget->item(index)->data(Qt::UserRole).toString()));
+ //m_view->setProfile(browser->profile(ui->listWidget->item(index)->data(Qt::UserRole).toString()));
m_view->show();
}
diff --git a/src/forms/profilesdialog.h b/src/forms/profilesdialog.h
index 71226e0..066fa7c 100644
--- a/src/forms/profilesdialog.h
+++ b/src/forms/profilesdialog.h
@@ -34,7 +34,7 @@ class ProfilesDialog : public QDialog
Q_OBJECT
public:
- explicit ProfilesDialog(MainWindow *window, QWidget *parent = 0);
+ explicit ProfilesDialog(MainWindow *window, QWidget *parent = nullptr);
~ProfilesDialog();
public slots:
diff --git a/src/main.cpp b/src/main.cpp
index 9df24b2..837e06c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -20,121 +20,144 @@
#include <iostream>
#include "browser.h"
-#include "mainwindow.h"
-#include <QApplication>
#include <QCommandLineParser>
+#include <QFile>
+#include <QStandardPaths>
+#include "mainwindow.h"
-/**
- * @brief printPoiToml Print the built-in config
- * @param output std::ostream to print to
- */
-void printPoiToml(std::ostream &output)
+// read config into std::string, supports qrc
+inline std::string readConfig(QString path)
{
- QFile conf(":/poi.toml");
+ QFile conf(path);
+ std::string ret;
if(conf.open(QIODevice::ReadOnly)) {
- output << conf.readAll().toStdString() << std::endl;
+ ret = conf.readAll().toStdString();
conf.close();
}
+ return ret;
+}
+
+bool writeUserConfig(const std::string &path, Configuration &config)
+{
+ // set firstRun to false so we don't re-init on every run
+ config.setValue<bool>("browser.firstRun", false);
+
+ // The .path's need to be overriden because ~ doesn't translate to home
+ const QString &home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
+
+ // profile.path
+ std::string profilePath = config.value<std::string>("profile.path").value();
+ config.setValue<std::string>("profile.path", patchHome(profilePath, home.toStdString()));
+
+ // bookmarks.path
+ std::string bookmarksPath = config.value<std::string>("bookmarks.path").value();
+ config.setValue<std::string>("bookmarks.path", patchHome(bookmarksPath, home.toStdString()));
+
+ // downloads.path
+ std::string downloadsPath = config.value<std::string>("downloads.path").value();
+ config.setValue<std::string>("downloads.path", patchHome(downloadsPath, home.toStdString()));
+
+ return config.writeUserConfiguration(path);
}
-const QHash<QString, QVariant> parseCommandLine(QApplication &app)
+int main(int argc, char *argv[])
{
+ // Create application object
+ Browser instance(argc, argv);
+
QCommandLineParser parser;
parser.setApplicationDescription("yet another Qt browser");
parser.addHelpOption();
parser.addVersionOption();
- QCommandLineOption configOption(QStringList() << "c" << "config", "Set configuration file.", "PATH");
+ // user config, ~/.config/smolbote/smolbote.cfg or empty if there is none
+ QCommandLineOption configOption({"c", "config"}, "Set configuration file.", "path");
+ configOption.setDefaultValue(QStandardPaths::locate(QStandardPaths::AppConfigLocation, "smolbote.cfg"));
parser.addOption(configOption);
- QCommandLineOption defaultConfigOption(QStringList() << "print-defaults", "Print default configuration.");
+ // default config, :/poi.cfg
+ QCommandLineOption defaultConfigOption("default-config", "Set the default configuration file.", "path");
+ defaultConfigOption.setDefaultValue(":/poi.cfg");
parser.addOption(defaultConfigOption);
- QCommandLineOption profileOption(QStringList() << "p" << "profile", "Use this profile.", "PROFILE");
- parser.addOption(profileOption);
+ // print default config, so users can easily create their overrides
+ QCommandLineOption printDefaultConfigOption("print-default-config", "Print default configuration.");
+ parser.addOption(printDefaultConfigOption);
- //QCommandLineOption nopluginsOption(QStringList() << "n" << "no-plugins", "Don't load plugins");
- //parser.addOption(nopluginsOption);
+ // generate user config
+ QCommandLineOption generateUserConfigOption("generate-user-config", "Generate user configuration and exit.");
+ parser.addOption(generateUserConfigOption);
- QCommandLineOption newInstanceOption(QStringList() << "new-instance", "Skip instance check at startup");
+ QCommandLineOption profileOption({"p", "profile"}, "Use this profile.", "PROFILE");
+ profileOption.setDefaultValue("");
+ parser.addOption(profileOption);
+
+ QCommandLineOption newInstanceOption("new-instance", "Skip instance check at startup");
parser.addOption(newInstanceOption);
- QCommandLineOption newWindowOption(QStringList() << "in-new-window", "Open URL in new window");
+ QCommandLineOption newWindowOption("in-new-window", "Open URL in new window");
parser.addOption(newWindowOption);
- QCommandLineOption newTabOption(QStringList() << "in-new-tab", "Open URL in new tab");
+ QCommandLineOption newTabOption("in-new-tab", "Open URL in new tab");
parser.addOption(newTabOption);
parser.addPositionalArgument("URL", "URL(s) to open");
- parser.process(app);
+ parser.process(instance);
- QHash<QString, QVariant> options;
- if(parser.isSet(configOption)) {
- options.insert("config", parser.value(configOption));
- }
- if(parser.isSet(defaultConfigOption)) {
- options.insert("print-defaults", true);
- }
- if(parser.isSet(profileOption)) {
- options.insert("profile", parser.value(profileOption));
- }
- if(parser.isSet(newInstanceOption)) {
- options.insert("new-instance", true);
- }
- if(parser.isSet(newWindowOption)) {
- options.insert("in-new-window", true);
- }
- if(parser.isSet(newTabOption)) {
- options.insert("in-new-tab", true);
- }
- options.insert("urls", parser.positionalArguments());
+#ifdef QT_DEBUG
+ qDebug("config=%s", qUtf8Printable(parser.value(configOption)));
+ qDebug("default-config=%s", qUtf8Printable(parser.value(defaultConfigOption)));
+#endif
- return options;
-}
+ if(parser.isSet(printDefaultConfigOption)) {
+ std::cout << readConfig(parser.value(defaultConfigOption));
+ std::cout.flush();
+ return 0;
+ }
-int main(int argc, char *argv[])
-{
- // Create application object
- Browser app(argc, argv);
-
- // program init
- {
- // parse command line options
- const QHash<QString, QVariant> options = parseCommandLine(app);
-
- // Check for another instance unless specified not to
- if(!options.contains("new-instance")) {
- app.bindLocalSocket();
- if(app.isRunning()) {
- qDebug("Another instance is running, returning...");
- app.sendMessage(options);
- return 0;
- }
+ std::shared_ptr<Configuration> config = std::make_shared<Configuration>();
+ config->readDefaultConfiguration(readConfig(parser.value(defaultConfigOption)));
+ config->readUserConfiguration(parser.value(configOption).toStdString());
+ instance.setConfiguration(config);
+
+ // check if first run
+ if(config->value<bool>("browser.firstRun").value() || parser.isSet(generateUserConfigOption)) {
+ // create a user config file
+ QString path = parser.value(configOption);
+ // there may be no smolbote.cfg
+ if(path.isEmpty()) {
+ path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/smolbote.cfg";
}
- if(options.contains("print-defaults")) {
- printPoiToml(std::cout);
+#ifdef QT_DEBUG
+ qDebug("Generating user config on first run to %s", qUtf8Printable(path));
+#endif
+
+ qDebug("Saving config to: %s - %s", qUtf8Printable(path), writeUserConfig(path.toStdString(), *config) ? "ok" : "failed");
+
+ if(parser.isSet(generateUserConfigOption)) {
return 0;
}
+ }
- app.setWindowIcon(QIcon(QLatin1String(":/icon.svg")));
- // This lets the web view automatically scale on high-dpi displays.
- app.setAttribute(Qt::AA_EnableHighDpiScaling);
-
- // Set configuration
- app.loadSettings(options.value("config", "").toString());
+ // TODO: instance check
- // Load profiles
- app.loadProfiles();
+ instance.loadProfiles();
- // Load plugins
- // if(!parser.isSet(nopluginsOption)) {
- // app.loadPlugins();
- // }
+ MainWindow* mainWindow = instance.createWindow();
+ if(parser.isSet(profileOption)) {
+ mainWindow->setProfile(instance.profile(parser.value(profileOption)));
+ }
- app.createWindow(options);
+ if(parser.positionalArguments().isEmpty()) {
+ // no URLs were given
+ mainWindow->newTab(QUrl::fromUserInput(config->value<std::string>("profile.homepage").value().c_str()));
+ } else {
+ for(const QString &url : parser.positionalArguments()) {
+ mainWindow->newTab(QUrl::fromUserInput(url));
+ }
}
- return app.exec();
+ return instance.exec();
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index daf344d..28a0ebb 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -22,9 +22,6 @@
#include "ui_mainwindow.h"
#include "widgets/mainwindowmenubar.h"
#include <QMessageBox>
-#include "browser.h"
-#include <QWebEngineDownloadItem>
-#include <QStatusBar>
#include "forms/aboutdialog.h"
#include <QToolButton>
@@ -36,7 +33,9 @@
#include <QDockWidget>
-MainWindow::MainWindow(QWidget *parent) :
+#include <settings/configuration.h>
+
+MainWindow::MainWindow(std::shared_ptr<Configuration> config, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
navigationToolBar(new QToolBar(tr("Navigation"), this)),
@@ -45,14 +44,17 @@ MainWindow::MainWindow(QWidget *parent) :
m_addressBar(new AddressBar(navigationToolBar)),
m_progressBar(new LoadingBar(this))
{
+ Q_ASSERT(config);
+ m_config = config;
+
// delete this window when it closes
setAttribute(Qt::WA_DeleteOnClose, true);
// set up UI
ui->setupUi(this);
QAction *fullscreenAction = new QAction(this);
- fullscreenAction->setShortcut(QKeySequence::fromString(browser->settings()->value("window.shortcuts.fullscreen").toString()));
- connect(fullscreenAction, SIGNAL(triggered(bool)), this, SLOT(toggleFullscreen()));
+ fullscreenAction->setShortcut(QKeySequence(QString::fromStdString(m_config->value<std::string>("browser.shortcuts.fullscreen").value())));
+ connect(fullscreenAction, &QAction::triggered, this, &MainWindow::toggleFullscreen);
addAction(fullscreenAction);
// Dockable widget styling
@@ -61,7 +63,7 @@ MainWindow::MainWindow(QWidget *parent) :
setTabPosition(Qt::RightDockWidgetArea, QTabWidget::North);
// Main menu
- MainWindowMenuBar *menuBar = new MainWindowMenuBar(this);
+ MainWindowMenuBar *menuBar = new MainWindowMenuBar(config, this);
menuBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
connect(menuBar->printAction(), &QAction::triggered, this, [&]() {
@@ -71,14 +73,14 @@ MainWindow::MainWindow(QWidget *parent) :
// Add the toolbars
// tabToolBar: main menu and tab list
- tabToolBar->setMovable(browser->settings()->value("window.ui.tabtoolbarMovable").toBool());
+ tabToolBar->setMovable(m_config->value<bool>("browser.ui.tabtoolbarMovable").value());
tabToolBar->addWidget(menuBar);
//tabToolBar->addWidget(tabBar);
this->addToolBar(Qt::TopToolBarArea, tabToolBar);
this->addToolBarBreak(Qt::TopToolBarArea);
// navigationToolBar: address bar
- navigationToolBar->setMovable(browser->settings()->value("window.ui.navtoolbarMovable").toBool());
+ navigationToolBar->setMovable(m_config->value<bool>("browser.ui.navtoolbarMovable").value());
// page actions
m_backButton = new NavigationButton(NavigationButton::BackButton, this);
@@ -107,18 +109,18 @@ MainWindow::MainWindow(QWidget *parent) :
connect(m_addressBar, &AddressBar::searchTermEntered, this, [&](const QString &string) {
QString term = string.mid(1);
term.replace(' ', '+');
- tabBar->currentView()->load(QUrl::fromUserInput(browser->settings()->value("general.search").toString().replace("$term", term)));
+ //tabBar->currentView()->load(QUrl::fromUserInput(browser->settings()->value("general.search").toString().replace("$term", term)));
});
connect(tabBar, SIGNAL(currentTabChanged(WebView*)), this, SLOT(handleTabChanged(WebView*)));
- connect(browser->bookmarks(), &BookmarksWidget::openUrl, this, [&](const QUrl &url) {
- if(this->isActiveWindow()) {
- this->newTab(url);
- }
- });
+// connect(browser->bookmarks(), &BookmarksWidget::openUrl, this, [&](const QUrl &url) {
+// if(this->isActiveWindow()) {
+// this->newTab(url);
+// }
+// });
// Load profile
- tabBar->setProfile(browser->profile(browser->settings()->value("browser.profile.default").toString()));
+ //tabBar->setProfile(browser->profile(browser->settings()->value("browser.profile.default").toString()));
// Adding a tab here, because otherwise tabs won't show up
//newTab();
@@ -127,12 +129,12 @@ MainWindow::MainWindow(QWidget *parent) :
// shortcuts
QAction *focusAddressAction = new QAction(this);
- focusAddressAction->setShortcut(QKeySequence::fromString(browser->settings()->value("window.shortcuts.focusAddress").toString()));
+ //focusAddressAction->setShortcut(QKeySequence::fromString(browser->settings()->value("window.shortcuts.focusAddress").toString()));
connect(focusAddressAction, SIGNAL(triggered(bool)), this, SLOT(focusAddress()));
addAction(focusAddressAction);
- resize(browser->settings()->value("window.width").toInt(), browser->settings()->value("window.height").toInt());
- if(browser->settings()->value("window.maximized").toBool()) {
+ resize(m_config->value<int>("browser.window.width").value(), m_config->value<int>("browser.window.height").value());
+ if(m_config->value<bool>("browser.window.maximized").value()) {
showMaximized();
}
}
@@ -144,7 +146,7 @@ MainWindow::~MainWindow()
QList<QDockWidget*> allDockWidgets = findChildren<QDockWidget*>();
for(QDockWidget *w : allDockWidgets) {
if(w->widget()) {
- w->widget()->setParent(0);
+ w->widget()->setParent(nullptr);
}
}
@@ -224,7 +226,7 @@ void MainWindow::newWindow(const QUrl &url)
{
QHash<QString, QVariant> options;
options.insert("urls", url);
- browser->createWindow(options);
+ //browser->createWindow(options);
}
void MainWindow::handleTabChanged(WebView *view)
@@ -236,7 +238,7 @@ void MainWindow::handleTabChanged(WebView *view)
// centralWidget can be a nullptr
if(centralWidget()) {
// clear the parent of the central widget so it doesn't get deleted
- centralWidget()->setParent(0);
+ centralWidget()->setParent(nullptr);
// disconnect signals
disconnect(centralWidget());
@@ -262,5 +264,9 @@ void MainWindow::handleTabChanged(WebView *view)
void MainWindow::handleTitleUpdated(const QString &title)
{
- setWindowTitle(browser->settings()->value("window.title").toString().replace("title", title).replace("profile", tabBar->profile()->name()));
+ QString t = QString::fromStdString(m_config->value<std::string>("browser.window.title").value());
+ t.replace("title", title);
+ t.replace("profile", tabBar->profile()->name());
+ setWindowTitle(t);
+ //setWindowTitle(browser->settings()->value("window.title").toString().replace("title", title).replace("profile", tabBar->profile()->name()));
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 5994f44..4a0c87d 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -34,17 +34,20 @@
#include "navigation/navigationbutton.h"
+#include <memory>
+
namespace Ui {
class MainWindow;
}
+class Configuration;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
- MainWindow(QWidget *parent = nullptr);
- ~MainWindow();
+ MainWindow(std::shared_ptr<Configuration> config, QWidget *parent = nullptr);
+ ~MainWindow() override;
void addTabbedDock(Qt::DockWidgetArea area, QWidget *widget);
@@ -80,6 +83,7 @@ private:
LoadingBar *m_progressBar;
bool m_tabBarAdded = false;
+ std::shared_ptr<Configuration> m_config;
};
#endif // MAINWINDOW_H
diff --git a/src/singleapplication.cpp b/src/singleapplication.cpp
index 331268b..2c74e6c 100644
--- a/src/singleapplication.cpp
+++ b/src/singleapplication.cpp
@@ -29,9 +29,11 @@ SingleApplication::SingleApplication(int &argc, char **argv) : QApplication(argc
SingleApplication::~SingleApplication()
{
- if(m_localServer->isListening()) {
- m_localServer->close();
- QLocalServer::removeServer(LOCALSERVER_KEY);
+ if(m_localServer) {
+ if(m_localServer->isListening()) {
+ m_localServer->close();
+ QLocalServer::removeServer(LOCALSERVER_KEY);
+ }
}
}
diff --git a/src/singleapplication.h b/src/singleapplication.h
index b512b34..aca1d3e 100644
--- a/src/singleapplication.h
+++ b/src/singleapplication.h
@@ -46,7 +46,7 @@ private:
const int LOCALSERVER_TIMEOUT = 500;
const QString LOCALSERVER_KEY = "smolbote_socket";
- QLocalServer *m_localServer;
+ QLocalServer *m_localServer = nullptr;
};
#endif // SINGLEAPPLICATION_H
diff --git a/src/webengine/webengineprofile.cpp b/src/webengine/webengineprofile.cpp
index 62f744e..52a740f 100644
--- a/src/webengine/webengineprofile.cpp
+++ b/src/webengine/webengineprofile.cpp
@@ -19,113 +19,104 @@
******************************************************************************/
#include "webengineprofile.h"
-#include "browser.h"
#include <QSettings>
#include <QWebEngineSettings>
-#include <QFile>
WebEngineProfile::WebEngineProfile(QObject *parent) :
QWebEngineProfile(parent)
{
m_name = tr("Off-the-record");
- // Off-the-record profiles have no persistent path
+#ifdef QT_DEBUG
+ qDebug("Creating off-the-record profile");
+#endif
- m_homepage = browser->settings()->value("browser.profile.new.homepage").toUrl();
- m_newtab = browser->settings()->value("browser.profile.new.newtab").toUrl();
+ // Off-the-record profiles have no persistent path
}
-WebEngineProfile::WebEngineProfile(const QString &name, QObject *parent) :
+WebEngineProfile::WebEngineProfile(const QString &name, const QString &path, QObject *parent) :
QWebEngineProfile(name, parent)
{
m_name = name;
- setPersistentStoragePath(browser->settings()->value("browser.profile.storagePath").toString() + name);
- setCachePath(browser->settings()->value("browser.profile.cachePath").toString() + name);
+
+#ifdef QT_DEBUG
+ qDebug("Creating profile %s", qUtf8Printable(m_name));
+#endif
+
+ setPersistentStoragePath(path + "/storage");
+ setCachePath(path + "/cache");
// Read profile settings
- QString profileIniPath = browser->settings()->value("browser.profile.path").toString() + name + "/profile.ini";
-
- // If none exist, use the defaults
- if(!QFile::exists(profileIniPath)) {
- qDebug("Creating new profile...");
- m_homepage = browser->settings()->value("browser.profile.new.homepage").toUrl();
- m_newtab = browser->settings()->value("browser.profile.new.newtab").toUrl();
-
- // Else read them
- } else {
-
- qDebug("Reading profile from [%s]", qUtf8Printable(profileIniPath));
- QSettings config(profileIniPath, QSettings::IniFormat);
-
- m_homepage = config.value("homepage", m_homepage).toUrl();
- m_newtab = config.value("newtab", m_newtab).toUrl();
-
- config.beginGroup("http");
- setHttpUserAgent(config.value("userAgent").toString());
- setHttpAcceptLanguage(config.value("accept-lang").toString());
- {
- QString cacheType = config.value("cacheType").toString();
- if(cacheType == "memory") {
- setHttpCacheType(MemoryHttpCache);
- } else if(cacheType == "disk") {
- setHttpCacheType(DiskHttpCache);
- } else if(cacheType == "disabled") {
- setHttpCacheType(NoCache);
- }
+ const QString profileIniPath = path + "/profile.ini";
+ qDebug("Reading profile from [%s]", qUtf8Printable(profileIniPath));
+ QSettings config(profileIniPath, QSettings::IniFormat);
+
+ m_homepage = config.value("homepage", m_homepage).toUrl();
+ m_newtab = config.value("newtab", m_newtab).toUrl();
+
+ config.beginGroup("http");
+ setHttpUserAgent(config.value("userAgent").toString());
+ setHttpAcceptLanguage(config.value("accept-lang").toString());
+ {
+ QString cacheType = config.value("cacheType").toString();
+ if(cacheType == "memory") {
+ setHttpCacheType(MemoryHttpCache);
+ } else if(cacheType == "disk") {
+ setHttpCacheType(DiskHttpCache);
+ } else if(cacheType == "disabled") {
+ setHttpCacheType(NoCache);
}
- setHttpCacheMaximumSize(config.value("cacheSize").toInt());
- config.endGroup(); // http
-
- config.beginGroup("policy");
- {
- QString cookies = config.value("cookies").toString();
- if(cookies == "disabled") {
- setPersistentCookiesPolicy(NoPersistentCookies);
- } else if(cookies == "allow") {
- setPersistentCookiesPolicy(AllowPersistentCookies);
- } else if(cookies == "force") {
- setPersistentCookiesPolicy(ForcePersistentCookies);
- }
+ }
+ setHttpCacheMaximumSize(config.value("cacheSize").toInt());
+ config.endGroup(); // http
+
+ config.beginGroup("policy");
+ {
+ QString cookies = config.value("cookies").toString();
+ if(cookies == "disabled") {
+ setPersistentCookiesPolicy(NoPersistentCookies);
+ } else if(cookies == "allow") {
+ setPersistentCookiesPolicy(AllowPersistentCookies);
+ } else if(cookies == "force") {
+ setPersistentCookiesPolicy(ForcePersistentCookies);
}
- config.endGroup(); // policy
-
- config.beginGroup("attributes");
- settings()->setAttribute(QWebEngineSettings::AutoLoadImages, config.value("autoLoadImages", true).toBool());
- settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, config.value("javascriptEnabled", true).toBool());
- settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, config.value("javascriptCanOpenWindows", true).toBool());
- settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, config.value("javascriptCanAccessClipboard", false).toBool());
- settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, config.value("linksIncludedInFocusChain", true).toBool());
- settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, config.value("localStorageEnabled", true).toBool());
- settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, config.value("localContentCanAccessRemoteUrls", false).toBool());
- settings()->setAttribute(QWebEngineSettings::XSSAuditingEnabled, config.value("xssAuditingEnabled", false).toBool());
- settings()->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, config.value("spatialNavigationEnabled", false).toBool());
- settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, config.value("localContentCanAccessFileUrls", true).toBool());
- settings()->setAttribute(QWebEngineSettings::HyperlinkAuditingEnabled, config.value("hyperlinkAuditingEnabled", false).toBool());
- settings()->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, config.value("scrollAnimatorEnabled", false).toBool());
- settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, config.value("errorPageEnabled", true).toBool());
- settings()->setAttribute(QWebEngineSettings::PluginsEnabled, config.value("pluginsEnabled", false).toBool());
- settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, config.value("fullscreenSupportEnabled", false).toBool());
- settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, config.value("screenCaptureEnabled", false).toBool());
- settings()->setAttribute(QWebEngineSettings::WebGLEnabled, config.value("webglEnabled", true).toBool());
- settings()->setAttribute(QWebEngineSettings::Accelerated2dCanvasEnabled, config.value("accelerated2dCanvasEnabled", true).toBool());
- settings()->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, config.value("autoLoadIconsForPage", true).toBool());
- settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, config.value("touchIconsEnabled", false).toBool());
- settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, config.value("focusOnNavigationEnabled", true).toBool());
- settings()->setAttribute(QWebEngineSettings::PrintElementBackgrounds, config.value("printElementBackgrounds", true).toBool());
- settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, config.value("allowRunningInsecureContent", false).toBool());
- config.endGroup(); // attributes
-
- } // QFile::exists(profilePath)
+ }
+ config.endGroup(); // policy
+
+ config.beginGroup("attributes");
+ settings()->setAttribute(QWebEngineSettings::AutoLoadImages, config.value("autoLoadImages", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, config.value("javascriptEnabled", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, config.value("javascriptCanOpenWindows", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, config.value("javascriptCanAccessClipboard", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, config.value("linksIncludedInFocusChain", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, config.value("localStorageEnabled", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, config.value("localContentCanAccessRemoteUrls", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::XSSAuditingEnabled, config.value("xssAuditingEnabled", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, config.value("spatialNavigationEnabled", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, config.value("localContentCanAccessFileUrls", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::HyperlinkAuditingEnabled, config.value("hyperlinkAuditingEnabled", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, config.value("scrollAnimatorEnabled", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, config.value("errorPageEnabled", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::PluginsEnabled, config.value("pluginsEnabled", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, config.value("fullscreenSupportEnabled", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, config.value("screenCaptureEnabled", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::WebGLEnabled, config.value("webglEnabled", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::Accelerated2dCanvasEnabled, config.value("accelerated2dCanvasEnabled", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, config.value("autoLoadIconsForPage", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, config.value("touchIconsEnabled", false).toBool());
+ settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, config.value("focusOnNavigationEnabled", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::PrintElementBackgrounds, config.value("printElementBackgrounds", true).toBool());
+ settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, config.value("allowRunningInsecureContent", false).toBool());
+ config.endGroup(); // attributes
+
+
}
WebEngineProfile::~WebEngineProfile()
{
- if(!isOffTheRecord()) {
+ if(shouldSaveProfile) {
saveProfile();
}
- if(m_profileDialog != nullptr) {
- m_profileDialog->deleteLater();
- }
}
QString WebEngineProfile::name() const
diff --git a/src/webengine/webengineprofile.h b/src/webengine/webengineprofile.h
index f457f53..c054349 100644
--- a/src/webengine/webengineprofile.h
+++ b/src/webengine/webengineprofile.h
@@ -23,14 +23,13 @@
#include <QWebEngineProfile>
#include <QUrl>
-#include "forms/profileview.h"
class WebEngineProfile : public QWebEngineProfile
{
Q_OBJECT
public:
- explicit WebEngineProfile(QObject *parent = Q_NULLPTR);
- explicit WebEngineProfile(const QString &name, QObject *parent = Q_NULLPTR);
+ explicit WebEngineProfile(QObject *parent = nullptr);
+ explicit WebEngineProfile(const QString &name, const QString &path, QObject *parent = nullptr);
~WebEngineProfile();
@@ -49,9 +48,9 @@ public slots:
private:
QString m_name;
+ bool shouldSaveProfile = false;
QUrl m_homepage = QUrl("about:blank");
QUrl m_newtab = QUrl("about:blank");
- ProfileView *m_profileDialog = nullptr;
};
#endif // WEBENGINEPROFILE_H
diff --git a/src/widgets/mainwindowmenubar.cpp b/src/widgets/mainwindowmenubar.cpp
index 964d9fd..c233d29 100644
--- a/src/widgets/mainwindowmenubar.cpp
+++ b/src/widgets/mainwindowmenubar.cpp
@@ -19,49 +19,61 @@
******************************************************************************/
#include "mainwindowmenubar.h"
+#include <QApplication>
#include <QMenu>
-#include "browser.h"
#include <QInputDialog>
#include "forms/profilesdialog.h"
-
-#include "interfaces.h"
-
#include "mainwindow.h"
+#include <settings/configuration.h>
-MainWindowMenuBar::MainWindowMenuBar(MainWindow *parent) :
+MainWindowMenuBar::MainWindowMenuBar(std::shared_ptr<Configuration> config, MainWindow *parent) :
QMenuBar(parent)
{
- m_parentWindow = parent;
+ Q_ASSERT(config);
+ Q_ASSERT(parent);
// Browser menu
QMenu *browserMenu = new QMenu(qApp->applicationName(), this);
addMenu(browserMenu);
- browserMenu->addAction(tr("New Window"), parent, SLOT(newWindow()), QKeySequence::fromString(browser->settings()->value("window.shortcuts.windowNew").toString()));
- browserMenu->addAction(tr("New Tab"), parent, SLOT(newTab()), QKeySequence::fromString(browser->settings()->value("window.shortcuts.tabNew").toString()));
+
+ QAction *newWindowAction = browserMenu->addAction(tr("New Window"));
+ connect(newWindowAction, &QAction::triggered, parent, [parent]() {
+ parent->newWindow();
+ });
+ newWindowAction->setShortcut(QKeySequence(config->value<std::string>("browser.shortcuts.newWindow").value().c_str()));
+
+ QAction *newTabAction = browserMenu->addAction(tr("New Tab"));
+ connect(newTabAction, &QAction::triggered, parent, [parent]() {
+ parent->newTab();
+ });
+ newTabAction->setShortcut(QKeySequence(config->value<std::string>("browser.shortcuts.newTab").value().c_str()));
+
browserMenu->addSeparator();
- browserMenu->addAction(tr("About"), parent, SLOT(about()), QKeySequence(tr("F1")));
- browserMenu->addAction(tr("About Qt"), qApp, SLOT(aboutQt()));
+ browserMenu->addAction(tr("About"), parent, &MainWindow::about, QKeySequence(config->value<std::string>("browser.shortcuts.about").value().c_str()));
+ browserMenu->addAction(tr("About Qt"), qApp, &QApplication::aboutQt);
browserMenu->addSeparator();
- browserMenu->addAction(tr("Quit"), qApp, SLOT(quit()), QKeySequence::fromString(browser->settings()->value("window.shortcuts.windowClose").toString()));
+
+ QAction *quitAction = browserMenu->addAction(tr("Quit"), qApp, &QApplication::quit);
+ quitAction->setShortcut(QKeySequence(config->value<std::string>("browser.shortcuts.quit").value().c_str()));
// Tools menu
QMenu *toolsMenu = new QMenu(tr("Tools"), this);
addMenu(toolsMenu);
QAction *downloadsAction = toolsMenu->addAction(tr("Downloads"));
downloadsAction->setParent(parent);
- downloadsAction->setShortcut(QKeySequence::fromString(browser->settings()->value("downloads.dialogShortcut").toString()));
- connect(downloadsAction, &QAction::triggered, this, [&]() {
- m_parentWindow->addTabbedDock(Qt::RightDockWidgetArea, browser->downloads());
- });
+ //downloadsAction->setShortcut(QKeySequence::fromString(browser->settings()->value("downloads.dialogShortcut").toString()));
+ //connect(downloadsAction, &QAction::triggered, this, [&]() {
+ // m_parentWindow->addTabbedDock(Qt::RightDockWidgetArea, browser->downloads());
+ //});
QAction *bookmarksAction = toolsMenu->addAction(tr("Bookmarks"));
bookmarksAction->setParent(parent);
- bookmarksAction->setShortcut(QKeySequence(browser->settings()->value("bookmarks.dialogShortcut").toString()));
- connect(bookmarksAction, &QAction::triggered, this, [&]() {
- m_parentWindow->addTabbedDock(Qt::RightDockWidgetArea, browser->bookmarks());
- });
+ //bookmarksAction->setShortcut(QKeySequence(browser->settings()->value("bookmarks.dialogShortcut").toString()));
+ //connect(bookmarksAction, &QAction::triggered, this, [&]() {
+ // m_parentWindow->addTabbedDock(Qt::RightDockWidgetArea, browser->bookmarks());
+ //});
toolsMenu->addSeparator();
- toolsMenu->addAction(tr("Filter"), browser->blocklists(), SLOT(show()), QKeySequence::fromString(browser->settings()->value("blocker.shortcut").toString()));
+ //toolsMenu->addAction(tr("Filter"), browser->blocklists(), SLOT(show()), QKeySequence::fromString(browser->settings()->value("blocker.shortcut").toString()));
// Plugins
// if(qApp->plugin("")) {
@@ -78,7 +90,7 @@ MainWindowMenuBar::MainWindowMenuBar(MainWindow *parent) :
// Profile menu
QMenu *profileMenu = new QMenu(tr("Profile"), this);
addMenu(profileMenu);
- profileMenu->addAction(tr("Profiles"), this, SLOT(handleLoadProfile()));
+ //profileMenu->addAction(tr("Profiles"), this, SLOT(handleLoadProfile()));
// Page menu
QMenu *pageMenu = new QMenu(tr("Page"), this);
@@ -93,9 +105,9 @@ QAction *MainWindowMenuBar::printAction()
return m_printAction;
}
-void MainWindowMenuBar::handleLoadProfile()
+void MainWindowMenuBar::handleLoadProfile(MainWindow *window)
{
- ProfilesDialog *dlg = new ProfilesDialog(m_parentWindow, this);
+ ProfilesDialog *dlg = new ProfilesDialog(window, this);
dlg->exec();
// bool ok;
diff --git a/src/widgets/mainwindowmenubar.h b/src/widgets/mainwindowmenubar.h
index 43c786b..e5e5f38 100644
--- a/src/widgets/mainwindowmenubar.h
+++ b/src/widgets/mainwindowmenubar.h
@@ -22,22 +22,22 @@
#define MAINWINDOWMENUBAR_H
#include <QMenuBar>
+#include <memory>
class MainWindow;
+class Configuration;
class MainWindowMenuBar : public QMenuBar
{
Q_OBJECT
public:
- explicit MainWindowMenuBar(MainWindow *parent = nullptr);
+ explicit MainWindowMenuBar(std::shared_ptr<Configuration> config, MainWindow *parent = nullptr);
QAction *printAction();
private slots:
- void handleLoadProfile();
+ void handleLoadProfile(MainWindow *window);
private:
- MainWindow *m_parentWindow;
-
QAction *m_printAction;
};
diff --git a/src/widgets/webviewtabbar.cpp b/src/widgets/webviewtabbar.cpp
index 1367e40..f8d3dc1 100644
--- a/src/widgets/webviewtabbar.cpp
+++ b/src/widgets/webviewtabbar.cpp
@@ -19,7 +19,6 @@
******************************************************************************/
#include "webviewtabbar.h"
-#include "browser.h"
#include <QAction>
#include <QContextMenuEvent>
#include <QMenu>
@@ -40,19 +39,19 @@ WebViewTabBar::WebViewTabBar(WebEngineProfile *profile, QWidget *parent) :
connect(this, SIGNAL(tabMoved(int,int)), this, SLOT(updateVectorArrangement(int,int)));
QShortcut *tabCloseShortcut = new QShortcut(this);
- tabCloseShortcut->setKey(QKeySequence::fromString(browser->settings()->value("window.shortcuts.tabClose").toString()));
+ //tabCloseShortcut->setKey(QKeySequence::fromString(browser->settings()->value("window.shortcuts.tabClose").toString()));
connect(tabCloseShortcut, &QShortcut::activated, [this]() {
this->removeTab(currentIndex());
});
QShortcut *tabLeftShortcut = new QShortcut(this);
- tabLeftShortcut->setKey(QKeySequence::fromString(browser->settings()->value("window.shortcuts.tabLeft").toString()));
+ //tabLeftShortcut->setKey(QKeySequence::fromString(browser->settings()->value("window.shortcuts.tabLeft").toString()));
connect(tabLeftShortcut, &QShortcut::activated, [this]() {
this->setCurrentIndex(currentIndex()-1);
});
QShortcut *tabRightShortcut = new QShortcut(this);
- tabRightShortcut->setKey(QKeySequence::fromString(browser->settings()->value("window.shortcuts.tabRight").toString()));
+ //tabRightShortcut->setKey(QKeySequence::fromString(browser->settings()->value("window.shortcuts.tabRight").toString()));
connect(tabRightShortcut, &QShortcut::activated, [this]() {
this->setCurrentIndex(currentIndex()+1);
});