aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix (xq) Queißner <git@mq32.de>2020-05-30 19:33:47 +0200
committerFelix (xq) Queißner <git@mq32.de>2020-05-30 19:33:47 +0200
commitea39cc542e17ce592dc3c4f2053d534bc458d88e (patch)
treec3c6a369d5b6d8a6a4e0b3e3667a56ca19e93173
parent79ff338a3427a236ef53adf806c56616faa3426c (diff)
downloadkristall-ea39cc542e17ce592dc3c4f2053d534bc458d88e.tar.gz
More usability, survives conmans torture nearly with 100%
-rw-r--r--README.md10
-rw-r--r--browsertab.cpp46
-rw-r--r--browsertab.hpp11
-rw-r--r--documentoutlinemodel.cpp131
-rw-r--r--documentoutlinemodel.hpp46
-rw-r--r--favouritecollection.cpp115
-rw-r--r--favouritecollection.hpp41
-rw-r--r--geminiclient.cpp10
-rw-r--r--geminiclient.hpp2
-rw-r--r--geminiwebpage.cpp12
-rw-r--r--geminiwebpage.hpp9
-rw-r--r--kristall.pro4
-rw-r--r--main.cpp2
-rw-r--r--mainwindow.cpp63
-rw-r--r--mainwindow.hpp19
-rw-r--r--mainwindow.ui27
16 files changed, 520 insertions, 28 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c62add1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# Kristall
+A high-quality visual cross-platform gemini browser.
+
+## TODO
+- [ ] Survive full torture suite
+ - [ ] Correctly parse mime parameters
+ - [ ] Correctly parse charset (0013, 0014)
+ - [ ] Correctly parse other params (0015)
+ - [ ] Correctly parse undefined params (0016)
+ - [ ] \ No newline at end of file
diff --git a/browsertab.cpp b/browsertab.cpp
index 7a14c24..46603b6 100644
--- a/browsertab.cpp
+++ b/browsertab.cpp
@@ -10,7 +10,9 @@
BrowserTab::BrowserTab(MainWindow * mainWindow) :
QWidget(nullptr),
ui(new Ui::BrowserTab),
- mainWindow(mainWindow)
+ mainWindow(mainWindow),
+ page(mainWindow),
+ outline()
{
ui->setupUi(this);
@@ -28,6 +30,8 @@ BrowserTab::BrowserTab(MainWindow * mainWindow) :
connect(&page, &GeminiWebPage::navigationRequest, this, &BrowserTab::on_navigationRequest);
ui->content->setPage(&page);
+
+ this->updateUI();
}
BrowserTab::~BrowserTab()
@@ -50,8 +54,11 @@ void BrowserTab::navigateTo(const QUrl &url)
}
this->redirection_count = 0;
+ this->successfully_loaded = false;
gemini_client.startRequest(url);
+
+ this->updateUI();
}
void BrowserTab::on_menu_button_clicked()
@@ -97,10 +104,12 @@ void BrowserTab::on_refresh_button_clicked()
void BrowserTab::on_gemini_complete(const QByteArray &data, const QString &mime)
{
if(mime.startsWith("text/gemini")) {
- this->page.setHtml(translateGeminiToHtml(data), this->current_location);
+ this->page.setHtml(translateGeminiToHtml(data, this->outline), this->current_location);
} else {
this->page.setContent(data, mime);
}
+ this->successfully_loaded = true;
+ this->updateUI();
}
void BrowserTab::on_protocolViolation(const QString &reason)
@@ -187,11 +196,13 @@ void BrowserTab::on_permanentFailure(PermanentFailure reason, const QString &inf
void BrowserTab::on_transientCertificateRequested(const QString &reason)
{
QMessageBox::warning(this, "Kristall", "Transient certificate requirested:\n" + reason);
+ this->updateUI();
}
void BrowserTab::on_authorisedCertificateRequested(const QString &reason)
{
QMessageBox::warning(this, "Kristall", "Authorized certificate requirested:\n" + reason);
+ this->updateUI();
}
void BrowserTab::on_certificateRejected(CertificateRejection reason, const QString &info)
@@ -231,7 +242,9 @@ void BrowserTab::on_navigationRequest(const QUrl &url, bool &allow)
void BrowserTab::setErrorMessage(const QString &msg)
{
- this->page.setContent(QString("An error happened:\n%0").arg(msg).toUtf8(), "text/plain charset=utf-8");
+ // this->page.setContent(QString("An error happened:\n%0").arg(msg).toUtf8(), "text/plain charset=utf-8");
+ QMessageBox::warning(this, "Kristall", msg);
+ this->updateUI();
}
void BrowserTab::pushToHistory(const QUrl &url)
@@ -240,13 +253,30 @@ void BrowserTab::pushToHistory(const QUrl &url)
this->updateUI();
}
+void BrowserTab::on_fav_button_clicked()
+{
+ if(this->ui->fav_button->isChecked()) {
+ this->mainWindow->favourites.add(this->current_location);
+ } else {
+ this->mainWindow->favourites.remove(this->current_location);
+ }
+
+ this->updateUI();
+}
+
+
void BrowserTab::updateUI()
{
this->ui->back_button->setEnabled(this->navigation_history.size() > 0);
this->ui->forward_button->setEnabled(false);
+
+ this->ui->refresh_button->setEnabled(this->successfully_loaded);
+
+ this->ui->fav_button->setEnabled(this->successfully_loaded);
+ this->ui->fav_button->setChecked(this->mainWindow->favourites.contains(this->current_location));
}
-QByteArray BrowserTab::translateGeminiToHtml(const QByteArray &input)
+QByteArray BrowserTab::translateGeminiToHtml(const QByteArray &input, DocumentOutlineModel & outline)
{
QByteArray result;
result.append(QString(R"html(<!doctype html>
@@ -260,6 +290,8 @@ QByteArray BrowserTab::translateGeminiToHtml(const QByteArray &input)
bool verbatim = false;
bool listing = false;
+ outline.beginBuild();
+
QList<QByteArray> lines = input.split('\n');
for(auto const & line : lines)
{
@@ -275,6 +307,7 @@ QByteArray BrowserTab::translateGeminiToHtml(const QByteArray &input)
}
else {
result.append(line);
+ result.append("\n");
}
} else {
if(line.startsWith("*")) {
@@ -296,16 +329,19 @@ QByteArray BrowserTab::translateGeminiToHtml(const QByteArray &input)
if(line.startsWith("###")) {
result.append("<h3>");
+ outline.appendH3(line.mid(3).trimmed());
result.append(line.mid(3).trimmed());
result.append("</h3>");
}
else if(line.startsWith("##")) {
result.append("<h2>");
+ outline.appendH2(line.mid(2).trimmed());
result.append(line.mid(2).trimmed());
result.append("</h2>");
}
else if(line.startsWith("#")) {
result.append("<h1>");
+ outline.appendH1(line.mid(1).trimmed());
result.append(line.mid(1).trimmed());
result.append("</h1>");
}
@@ -349,6 +385,8 @@ QByteArray BrowserTab::translateGeminiToHtml(const QByteArray &input)
}
}
+ outline.endBuild();
+
result.append(QString(R"html(
</body>
</html>
diff --git a/browsertab.hpp b/browsertab.hpp
index 47ee473..ddaf1b4 100644
--- a/browsertab.hpp
+++ b/browsertab.hpp
@@ -6,6 +6,7 @@
#include "geminiclient.hpp"
#include "geminiwebpage.hpp"
+#include "documentoutlinemodel.hpp"
namespace Ui {
class BrowserTab;
@@ -61,6 +62,8 @@ private slots:
void on_navigationRequest(QUrl const & url, bool & allow);
+ void on_fav_button_clicked();
+
private:
void setErrorMessage(QString const & msg);
@@ -68,9 +71,9 @@ private:
void updateUI();
- QByteArray translateGeminiToHtml(QByteArray const & input);
+ static QByteArray translateGeminiToHtml(QByteArray const & input, DocumentOutlineModel & outline);
-private:
+public:
Ui::BrowserTab *ui;
MainWindow * mainWindow;
QUrl current_location;
@@ -81,6 +84,10 @@ private:
QVector<QUrl> navigation_history;
GeminiWebPage page;
+
+ bool successfully_loaded = false;
+
+ DocumentOutlineModel outline;
};
#endif // BROWSERTAB_HPP
diff --git a/documentoutlinemodel.cpp b/documentoutlinemodel.cpp
new file mode 100644
index 0000000..1787d9e
--- /dev/null
+++ b/documentoutlinemodel.cpp
@@ -0,0 +1,131 @@
+#include "documentoutlinemodel.hpp"
+
+#include <QModelIndex>
+
+DocumentOutlineModel::DocumentOutlineModel() :
+ QAbstractItemModel(),
+ root()
+{
+
+}
+
+void DocumentOutlineModel::beginBuild()
+{
+ beginResetModel();
+ root = Node {
+ nullptr,
+ "<ROOT>",
+ 0,
+ QVector<Node> { },
+};
+}
+
+void DocumentOutlineModel::appendH1(const QString &title)
+{
+ root.children.append(Node {
+ &root,
+ title,
+ 1,
+ QVector<Node> { },
+ });
+}
+
+void DocumentOutlineModel::appendH2(const QString &title)
+{
+ if(root.children.size() == 0) {
+ root.children.append(Node {
+ &root,
+ "<missing layer>",
+ 1,
+ QVector<Node> { },
+ });
+ }
+ auto & parent = root.children.last();
+ parent.children.append(Node {
+ &parent,
+ title,
+ 2,
+ QVector<Node> { },
+ });
+}
+
+void DocumentOutlineModel::appendH3(const QString &title)
+{
+
+}
+
+void DocumentOutlineModel::endBuild()
+{
+ endResetModel();
+}
+
+QModelIndex DocumentOutlineModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (not hasIndex(row, column, parent))
+ return QModelIndex();
+
+ Node const * parentItem;
+
+ if (!parent.isValid())
+ parentItem = &this->root;
+ else
+ parentItem = static_cast<Node*>(parent.internalPointer());
+
+ Node const * childItem = &parentItem->children[row];
+ if (childItem)
+ return createIndex(row, column, reinterpret_cast<quintptr>(childItem));
+ return QModelIndex();
+
+}
+
+QModelIndex DocumentOutlineModel::parent(const QModelIndex &child) const
+{
+ if (!child.isValid())
+ return QModelIndex();
+
+ Node const *childItem = static_cast<Node const *>(child.internalPointer());
+ Node const * parent = childItem->parent;
+
+ if (parent == &root)
+ return QModelIndex();
+
+ return createIndex(
+ parent - parent->parent->children.data(),
+ 0,
+ reinterpret_cast<quintptr>(parent));
+}
+
+int DocumentOutlineModel::rowCount(const QModelIndex &parent) const
+{
+ Node const *parentItem;
+ if (parent.column() > 0)
+ return 0;
+
+ if (!parent.isValid())
+ parentItem = &root;
+ else
+ parentItem = static_cast<Node const *>(parent.internalPointer());
+
+ return parentItem->children.size();
+}
+
+int DocumentOutlineModel::columnCount(const QModelIndex &parent) const
+{
+ return 1;
+}
+
+QVariant DocumentOutlineModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (index.column() != 0)
+ return QVariant();
+
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ Node const *item = static_cast<Node const*>(index.internalPointer());
+
+ return item->title;
+}
diff --git a/documentoutlinemodel.hpp b/documentoutlinemodel.hpp
new file mode 100644
index 0000000..802bd86
--- /dev/null
+++ b/documentoutlinemodel.hpp
@@ -0,0 +1,46 @@
+#ifndef DOCUMENTOUTLINEMODEL_HPP
+#define DOCUMENTOUTLINEMODEL_HPP
+
+#include <QAbstractItemModel>
+
+class DocumentOutlineModel :
+ public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ DocumentOutlineModel();
+
+ void beginBuild();
+
+ void appendH1(QString const & title);
+
+ void appendH2(QString const & title);
+
+ void appendH3(QString const & title);
+
+ void endBuild();
+
+public:
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+
+ QModelIndex parent(const QModelIndex &child) const override;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+
+private:
+ struct Node
+ {
+ Node * parent;
+ QString title;
+ int depth = 0;
+ QVector<Node> children;
+ };
+
+ Node root;
+};
+
+#endif // DOCUMENTOUTLINEMODEL_HPP
diff --git a/favouritecollection.cpp b/favouritecollection.cpp
new file mode 100644
index 0000000..79409bb
--- /dev/null
+++ b/favouritecollection.cpp
@@ -0,0 +1,115 @@
+#include "favouritecollection.hpp"
+
+#include <QFile>
+
+FavouriteCollection::FavouriteCollection(QObject *parent) :
+ QAbstractListModel(parent)
+{
+
+}
+
+void FavouriteCollection::add(QUrl const & url)
+{
+ if(contains(url))
+ return;
+
+ beginInsertRows(QModelIndex{}, items.size(), items.size() + 1);
+ items.push_back(url);
+ endInsertRows();
+}
+
+void FavouriteCollection::remove(QUrl const & url)
+{
+ for(int i = 0; i < items.size(); i++)
+ {
+ if(items.at(i) == url) {
+ beginRemoveRows(QModelIndex{}, i, i + 1);
+ items.removeAt(i);
+ endRemoveRows();
+ return;
+ }
+ }
+}
+
+bool FavouriteCollection::contains(const QUrl &url)
+{
+ for(auto const & item : items) {
+ if(item == url)
+ return true;
+ }
+ return false;
+}
+
+QUrl FavouriteCollection::get(const QModelIndex &index) const
+{
+ if(index.isValid()) {
+ return items.at(index.row());
+ } else {
+ return QUrl { };
+ }
+}
+
+bool FavouriteCollection::save(const QString &fileName) const
+{
+ QFile file(fileName);
+ if(not file.open(QFile::WriteOnly))
+ return false;
+
+ for(auto const & url: items)
+ {
+ QByteArray blob = (url.toString() + "\n").toUtf8();
+
+ qint64 offset = 0;
+ while(offset < blob.size())
+ {
+ auto len = file.write(blob.data() + offset, blob.size() - offset);
+ if(len <= 0) {
+ file.close();
+ return false;
+ }
+ offset += len;
+ }
+ }
+
+ file.close();
+ return true;
+}
+
+bool FavouriteCollection::load(const QString &fileName)
+{
+ QFile file(fileName);
+ if(not file.open(QFile::ReadOnly))
+ return false;
+ auto data = file.readAll();
+
+ beginResetModel();
+
+ items.clear();
+ for(auto line : data.split('\n')) {
+ if(line.size() > 0) {
+ items.push_back(QUrl(QString::fromUtf8(line)));
+ }
+ }
+ endResetModel();
+
+ return true;
+}
+
+int FavouriteCollection::rowCount(const QModelIndex &parent) const
+{
+ return items.size();
+}
+
+bool FavouriteCollection::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ return false;
+}
+
+QVariant FavouriteCollection::data(const QModelIndex &index, int role) const
+{
+ if(role != Qt::DisplayRole) {
+ return QVariant{};
+ }
+ return items.at(index.row()).toString();
+}
+
diff --git a/favouritecollection.hpp b/favouritecollection.hpp
new file mode 100644
index 0000000..dd68b93
--- /dev/null
+++ b/favouritecollection.hpp
@@ -0,0 +1,41 @@
+#ifndef FAVOURITECOLLECTION_HPP
+#define FAVOURITECOLLECTION_HPP
+
+#include <QObject>
+#include <QAbstractListModel>
+#include <QUrl>
+
+
+class FavouriteCollection : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ explicit FavouriteCollection(QObject *parent = nullptr);
+
+ void add(QUrl const & url);
+
+ void remove(QUrl const & url);
+
+ bool contains(QUrl const & url);
+
+ QUrl get(QModelIndex const & index) const ;
+
+ bool save(QString const & fileName) const;
+
+ bool load(QString const & fileName);
+
+public:
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+signals:
+
+private:
+ QVector<QUrl> items;
+
+};
+
+#endif // FAVOURITECOLLECTION_HPP
diff --git a/geminiclient.cpp b/geminiclient.cpp
index 4a914a3..57e1679 100644
--- a/geminiclient.cpp
+++ b/geminiclient.cpp
@@ -7,6 +7,7 @@ GeminiClient::GeminiClient(QObject *parent) : QObject(parent)
connect(&socket, &QSslSocket::encrypted, this, &GeminiClient::socketEncrypted);
connect(&socket, &QSslSocket::readyRead, this, &GeminiClient::socketReadyRead);
connect(&socket, &QSslSocket::disconnected, this, &GeminiClient::socketDisconnected);
+ connect(&socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), this, &GeminiClient::sslErrors);
}
bool GeminiClient::startRequest(const QUrl &url)
@@ -218,3 +219,12 @@ void GeminiClient::socketDisconnected()
emit requestComplete(body, mime_type);
}
}
+
+void GeminiClient::sslErrors(const QList<QSslError> &errors)
+{
+ for(auto const & error : errors) {
+ qDebug() << error.errorString() ;
+ }
+
+ socket.ignoreSslErrors(errors);
+}
diff --git a/geminiclient.hpp b/geminiclient.hpp
index 5f0a38a..71256c0 100644
--- a/geminiclient.hpp
+++ b/geminiclient.hpp
@@ -69,6 +69,8 @@ private slots:
void socketDisconnected();
+ void sslErrors(const QList<QSslError> &errors);
+
private:
bool is_receiving_body;
diff --git a/geminiwebpage.cpp b/geminiwebpage.cpp
index 3ac41aa..1cbd130 100644
--- a/geminiwebpage.cpp
+++ b/geminiwebpage.cpp
@@ -1,6 +1,9 @@
#include "geminiwebpage.hpp"
+#include "browsertab.hpp"
-GeminiWebPage::GeminiWebPage(QObject *parent) : QWebEnginePage(parent)
+GeminiWebPage::GeminiWebPage(MainWindow * container) :
+ QWebEnginePage(),
+ main_window(container)
{
}
@@ -32,3 +35,10 @@ bool GeminiWebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::Nav
return false;
}
}
+
+QWebEnginePage *GeminiWebPage::createWindow(QWebEnginePage::WebWindowType type)
+{
+ auto tab = main_window->addEmptyTab(true);
+
+ return &tab->page;
+}
diff --git a/geminiwebpage.hpp b/geminiwebpage.hpp
index 94c6a82..a5de627 100644
--- a/geminiwebpage.hpp
+++ b/geminiwebpage.hpp
@@ -3,20 +3,25 @@
#include <QObject>
#include <QWebEnginePage>
+#include "mainwindow.hpp"
class GeminiWebPage : public QWebEnginePage
{
Q_OBJECT
public:
- explicit GeminiWebPage(QObject *parent = nullptr);
+ explicit GeminiWebPage(MainWindow * container);
signals:
void navigationRequest(QUrl const & url, bool & allow);
protected:
- bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame);
+ bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) override;
+ QWebEnginePage *createWindow(QWebEnginePage::WebWindowType type) override;
+
+private:
+ MainWindow * main_window;
};
#endif // GEMINIWEBPAGE_HPP
diff --git a/kristall.pro b/kristall.pro
index 834ee5b..20a3219 100644
--- a/kristall.pro
+++ b/kristall.pro
@@ -17,6 +17,8 @@ DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
browsertab.cpp \
+ documentoutlinemodel.cpp \
+ favouritecollection.cpp \
geminiclient.cpp \
geminiwebpage.cpp \
main.cpp \
@@ -24,6 +26,8 @@ SOURCES += \
HEADERS += \
browsertab.hpp \
+ documentoutlinemodel.hpp \
+ favouritecollection.hpp \
geminiclient.hpp \
geminiwebpage.hpp \
mainwindow.hpp
diff --git a/main.cpp b/main.cpp
index f882918..6b557ab 100644
--- a/main.cpp
+++ b/main.cpp
@@ -8,7 +8,7 @@ int main(int argc, char *argv[])
QApplication a(argc, argv);
MainWindow w;
- w.addNewTab(QUrl("gemini://gemini.circumlunar.space/"));
+ w.addNewTab(true, QUrl("gemini://gemini.circumlunar.space/"));
w.show();
return a.exec();
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 9e5c3df..75cdeba 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -12,36 +12,77 @@ MainWindow::MainWindow(QWidget *parent)
ui->setupUi(this);
this->statusBar()->addWidget(this->url_status);
+
+ this->favourites.load("./favourites.db");
+
+ ui->favourites_view->setModel(&favourites);
}
MainWindow::~MainWindow()
{
+ this->favourites.save("./favourites.db");
delete ui;
}
-void MainWindow::addEmptyTab()
+BrowserTab * MainWindow::addEmptyTab(bool focus_new)
{
- auto tab = std::make_unique<BrowserTab>(this);
+ BrowserTab * tab = new BrowserTab(this);
+ int index = this->ui->browser_tabs->addTab(tab, "Page");
+ if(focus_new) {
+ this->ui->browser_tabs->setCurrentIndex(index);
+ }
- this->ui->browser_tabs->addTab(tab.release(), "Page");
+ return tab;
}
-void MainWindow::addNewTab(QUrl const & url)
+BrowserTab * MainWindow::addNewTab(bool focus_new, QUrl const & url)
{
- auto tab = std::make_unique<BrowserTab>(this);
-
+ auto tab = addEmptyTab(focus_new);
tab->navigateTo(url);
-
- this->ui->browser_tabs->addTab(tab.release(), "Page");
+ return tab;
}
void MainWindow::setUrlPreview(const QUrl &url)
{
- if(url.isValid())
- this->url_status->setText(url.toString());
- else
+ if(url.isValid()) {
+ auto str = url.toString();
+ if(str.length() > 300) {
+ str = str.mid(0, 300) + "...";
+ }
+ this->url_status->setText(str);
+ }
+ else {
this->url_status->setText("");
+ }
+}
+
+
+void MainWindow::on_browser_tabs_currentChanged(int index)
+{
+ if(index >= 0) {
+ BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->widget(index));
+
+ if(tab != nullptr) {
+ this->ui->outline_view->setModel(&tab->outline);
+ this->ui->outline_view->expandAll();
+ } else {
+ this->ui->outline_view->setModel(nullptr);
+ }
+ } else {
+ this->ui->outline_view->setModel(nullptr);
+ }
}
+void MainWindow::on_favourites_view_doubleClicked(const QModelIndex &index)
+{
+ if(auto url = this->favourites.get(index); url.isValid()) {
+ this->addNewTab(true, url);
+ }
+}
+
+void MainWindow::on_browser_tabs_tabCloseRequested(int index)
+{
+ delete this->ui->browser_tabs->widget(index);
+}
diff --git a/mainwindow.hpp b/mainwindow.hpp
index b9da644..0481011 100644
--- a/mainwindow.hpp
+++ b/mainwindow.hpp
@@ -4,10 +4,14 @@
#include <QMainWindow>
#include <QLabel>
+#include "favouritecollection.hpp"
+
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
+class BrowserTab;
+
class MainWindow : public QMainWindow
{
Q_OBJECT
@@ -17,14 +21,25 @@ public:
~MainWindow();
- void addEmptyTab();
- void addNewTab(QUrl const & url);
+ BrowserTab * addEmptyTab(bool focus_new);
+ BrowserTab * addNewTab(bool focus_new, QUrl const & url);
void setUrlPreview(QUrl const & url);
+public:
+ FavouriteCollection favourites;
+
+private slots:
+ void on_browser_tabs_currentChanged(int index);
+
+ void on_favourites_view_doubleClicked(const QModelIndex &index);
+
+ void on_browser_tabs_tabCloseRequested(int index);
+
private:
Ui::MainWindow *ui;
QLabel * url_status;
+
};
#endif // MAINWINDOW_HPP
diff --git a/mainwindow.ui b/mainwindow.ui
index 5befe13..652857a 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -74,12 +74,23 @@
<number>0</number>
</property>
<item>
- <widget class="QTreeView" name="treeView"/>
+ <widget class="QTreeView" name="outline_view">
+ <property name="autoExpandDelay">
+ <number>0</number>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ </widget>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="bookmarks_window">
+ <property name="windowIcon">
+ <iconset resource="icons.qrc">
+ <normaloff>:/icons/heart.svg</normaloff>:/icons/heart.svg</iconset>
+ </property>
<property name="windowTitle">
<string>Bookmarks</string>
</property>
@@ -101,7 +112,7 @@
<number>0</number>
</property>
<item>
- <widget class="QTreeView" name="treeView_2"/>
+ <widget class="QListView" name="favourites_view"/>
</item>
</layout>
</widget>
@@ -128,7 +139,7 @@
<number>0</number>
</property>
<item>
- <widget class="QListView" name="listView"/>
+ <widget class="QListView" name="history_view"/>
</item>
</layout>
</widget>
@@ -155,12 +166,18 @@
<number>0</number>
</property>
<item>
- <widget class="QTreeView" name="treeView_3"/>
+ <widget class="QTreeView" name="clientcert_view">
+ <property name="headerHidden">
+ <bool>true</bool>
+ </property>
+ </widget>
</item>
</layout>
</widget>
</widget>
</widget>
- <resources/>
+ <resources>
+ <include location="icons.qrc"/>
+ </resources>
<connections/>
</ui>