summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Dywan <christian@twotoasts.de>2018-09-10 14:29:34 +0200
committerChristian Dywan <christian@twotoasts.de>2018-09-10 14:40:29 +0200
commit61dfc0f36e360372d4b2334a232ef7f7ae2f6471 (patch)
tree551184a83915942820a45b289907b11374967165
parent2e94e9866b42e2ccf7cd0fa7677b7ecb11de151f (diff)
downloadmidori-git-tabby.tar.gz
Implement built-in session extensiontabby
Closes: #41
-rw-r--r--core/database.vala4
-rw-r--r--data/tabby/Create.sql33
-rw-r--r--data/tabby/Update1.sql4
-rw-r--r--extensions/session.plugin.in5
-rw-r--r--extensions/session.vala175
-rw-r--r--po/POTFILES.in1
6 files changed, 220 insertions, 2 deletions
diff --git a/core/database.vala b/core/database.vala
index 748f54c3..92b57478 100644
--- a/core/database.vala
+++ b/core/database.vala
@@ -459,7 +459,7 @@ namespace Midori {
/*
* Update an existing item, where URI and date match.
*/
- public async bool update (DatabaseItem item) throws DatabaseError {
+ public async virtual bool update (DatabaseItem item) throws DatabaseError {
string sqlcmd = """
UPDATE %s SET title=:title WHERE uri = :uri AND date=:date
""".printf (table);
@@ -484,7 +484,7 @@ namespace Midori {
/*
* Insert an item into the database.
*/
- public async bool insert (DatabaseItem item) throws DatabaseError {
+ public async virtual bool insert (DatabaseItem item) throws DatabaseError {
item.database = this;
string sqlcmd = """
diff --git a/data/tabby/Create.sql b/data/tabby/Create.sql
new file mode 100644
index 00000000..0b5690bd
--- /dev/null
+++ b/data/tabby/Create.sql
@@ -0,0 +1,33 @@
+CREATE TABLE IF NOT EXISTS sessions
+(
+ id INTEGER PRIMARY KEY,
+ parent_id INTEGER DEFAULT 0,
+ crdate INTEGER DEFAULT 0,
+ tstamp INTEGER DEFAULT 0,
+ closed INTEGER DEFAULT 0,
+ title TEXT DEFAULT NULL,
+ FOREIGN KEY(parent_id) REFERENCES sessions(id)
+);
+
+CREATE TABLE IF NOT EXISTS tabs
+(
+ id INTEGER PRIMARY KEY,
+ session_id INTEGER NOT NULL,
+ uri TEXT DEFAULT NULL,
+ icon TEXT DEFAULT NULL,
+ title TEXT DEFAULT NULL,
+ crdate INTEGER DEFAULT 0,
+ tstamp INTEGER DEFAULT 0,
+ closed INTEGER DEFAULT 0,
+ FOREIGN KEY(session_id) REFERENCES sessions(id)
+);
+
+CREATE TABLE IF NOT EXISTS tab_history
+(
+ id INTEGER PRIMARY KEY,
+ tab_id INTEGER,
+ url TEXT,
+ icon TEXT,
+ title TEXT,
+ FOREIGN KEY(tab_id) REFERENCES tabs(id)
+);
diff --git a/data/tabby/Update1.sql b/data/tabby/Update1.sql
new file mode 100644
index 00000000..26b72103
--- /dev/null
+++ b/data/tabby/Update1.sql
@@ -0,0 +1,4 @@
+ALTER TABLE tabs ADD sorting REAL DEFAULT 0;
+
+CREATE INDEX sorting on tabs (sorting ASC);
+CREATE INDEX tstamp on tabs (tstamp ASC);
diff --git a/extensions/session.plugin.in b/extensions/session.plugin.in
new file mode 100644
index 00000000..baa5cf5b
--- /dev/null
+++ b/extensions/session.plugin.in
@@ -0,0 +1,5 @@
+[Plugin]
+Module=session
+IAge=3
+Name=Session
+Builtin=true
diff --git a/extensions/session.vala b/extensions/session.vala
new file mode 100644
index 00000000..5d667767
--- /dev/null
+++ b/extensions/session.vala
@@ -0,0 +1,175 @@
+/*
+ Copyright (C) 2013-2018 Christian Dywan <christian@twotoats.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ See the file COPYING for the full license text.
+*/
+
+namespace Tabby {
+ class SessionDatabase : Midori.Database {
+ int64 id { get; set; }
+
+ static SessionDatabase? _default = null;
+
+ public static SessionDatabase get_default () throws Midori.DatabaseError {
+ if (_default == null) {
+ _default = new SessionDatabase ();
+ }
+ return _default;
+ }
+
+ SessionDatabase () throws Midori.DatabaseError {
+ Object (path: "tabby.db", table: "tabs");
+ init ();
+ }
+
+ public async override List<Midori.DatabaseItem>? query (string? filter=null, int64 max_items=15, Cancellable? cancellable=null) throws Midori.DatabaseError {
+ string where = filter != null ? "WHERE uri LIKE :filter OR title LIKE :filter" : "";
+ string sqlcmd = """
+ SELECT id, uri, title, tstamp, sorting FROM %s
+ %s
+ ORDER BY tstamp DESC LIMIT :limit
+ """.printf (table, where);
+ Midori.DatabaseStatement statement;
+ try {
+ statement = prepare (sqlcmd,
+ ":limit", typeof (int64), max_items);
+ if (filter != null) {
+ string real_filter = "%" + filter.replace (" ", "%") + "%";
+ statement.bind (":filter", typeof (string), real_filter);
+ }
+ } catch (Midori.DatabaseError error) {
+ throw new Midori.DatabaseError.EXECUTE ("Failed to select from %s: %s".printf (table, error.message));
+ }
+
+ var items = new List<Midori.DatabaseItem> ();
+ try {
+ while (statement.step ()) {
+ string uri = statement.get_string ("uri");
+ string title = statement.get_string ("title");
+ int64 date = statement.get_int64 ("tstamp");
+ var item = new Midori.DatabaseItem (uri, title, date);
+ item.database = this;
+ item.id = statement.get_int64 ("id");
+ item.set_data<double?> ("sorting", statement.get_double ("sorting"));
+ items.append (item);
+
+ uint src = Idle.add (query.callback);
+ yield;
+ Source.remove (src);
+
+ if (cancellable != null && cancellable.is_cancelled ())
+ return null;
+ }
+ } catch (Midori.DatabaseError error) {
+ throw new Midori.DatabaseError.EXECUTE ("Failed to select from %s: %s".printf (table, error.message));
+ }
+
+ if (cancellable != null && cancellable.is_cancelled ())
+ return null;
+ return items;
+ }
+
+ public async override bool insert (Midori.DatabaseItem item) throws Midori.DatabaseError {
+ item.database = this;
+
+ string sqlcmd = """
+ INSERT INTO %s (crdate, tstamp, session_id, uri, title, sorting)
+ VALUES (:crdate, :tstamp, :session_id, :uri, :title, :sorting)
+ """.printf (table);
+
+ var statement = prepare (sqlcmd,
+ ":crdate", typeof (int64), new DateTime.now_local ().to_unix (),
+ ":tstamp", typeof (int64), item.date,
+ ":session_id", typeof (int64), id,
+ ":uri", typeof (string), item.uri,
+ ":title", typeof (string), item.title,
+ ":sorting", typeof (double), item.get_data<double?> ("sorting") ?? 1);
+ if (statement.exec ()) {
+ item.id = statement.row_id ();
+ /* XXX: if (_items != null) {
+ _items.append (item);
+ items_changed (_items.index (item), 0, 1);
+ } */
+ return true;
+ }
+ return false;
+ }
+
+ public async override bool update (Midori.DatabaseItem item) throws Midori.DatabaseError {
+ string sqlcmd = """
+ UPDATE %s SET uri=:uri, title=:title, tstamp=:tstamp WHERE rowid=:id
+ """.printf (table);
+ try {
+ var statement = prepare (sqlcmd,
+ ":id", typeof (int64), item.id,
+ ":uri", typeof (string), item.uri,
+ ":title", typeof (string), item.title,
+ ":tstamp", typeof (int64), item.date);
+ if (statement.exec ()) {
+ /* XXX: if (_items != null) {
+ items_changed (_items.index (item), 0, 0);
+ } */
+ return true;
+ }
+ } catch (Error error) {
+ critical ("Failed to update %s: %s", table, error.message);
+ }
+ return false;
+ }
+
+ // XXX: save/ restore tab trash
+ // XXX: don't add restored tabs to history
+
+ public async void restore_session (Midori.Browser browser) throws Midori.DatabaseError {
+ /* XXX:
+ string sqlcmd = "SELECT id, uri, title, sorting FROM tabs WHERE session_id = :session_id ORDER BY tstamp DESC";
+ string sqlcmd = "SELECT MAX(sorting) FROM tabs WHERE session_id = :session_id";
+ string sqlcmd = """
+ SELECT id, closed FROM sessions WHERE closed = 0
+ UNION
+ SELECT * FROM (SELECT id, closed FROM sessions WHERE closed = 1 ORDER BY tstamp DESC LIMIT 1)
+ ORDER BY closed;
+ """;
+ */
+ // XXX: id = 1234;
+ foreach (var item in yield query ()) {
+ var tab = new Midori.Tab (browser.tab, browser.web_context,
+ item.uri, item.title);
+ tab.notify["uri"].connect ((pspec) => { update.begin (item); });
+ tab.notify["title"].connect ((pspec) => { item.title = tab.title; });
+ // XXX: add new tabs
+ // XXX: add new windows
+ // XXX: drop closed tabs
+ browser.add (tab);
+ }
+ }
+ }
+
+ public class BrowserSession : Peas.ExtensionBase, Midori.BrowserActivatable {
+ public Midori.Browser browser { owned get; set; }
+
+ public void activate () {
+ activate_async.begin ();
+ }
+
+ async void activate_async () {
+ try {
+ yield SessionDatabase.get_default ().restore_session (browser);
+ } catch (Midori.DatabaseError error) {
+ critical ("Failed to restore session: %s", error.message);
+ }
+ }
+ }
+}
+
+[ModuleInit]
+public void peas_register_types(TypeModule module) {
+ ((Peas.ObjectModule)module).register_extension_type (
+ typeof (Midori.BrowserActivatable), typeof (Tabby.BrowserSession));
+
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 77c0d2e3..6df60daf 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -22,6 +22,7 @@ core/switcher.vala
core/tab.vala
core/tally.vala
core/urlbar.vala
+extensions/session.vala
ui/browser.ui
ui/clear-private-data.ui
ui/download-button.ui