Merge lp:~ivaldi/midori/tabby-tab-order into lp:midori

Proposed by André Stösel
Status: Merged
Approved by: Cris Dywan
Approved revision: 6407
Merged at revision: 6427
Proposed branch: lp:~ivaldi/midori/tabby-tab-order
Merge into: lp:midori
Diff against target: 284 lines (+150/-7)
3 files modified
data/tabby/Update1.sql (+4/-0)
extensions/tabby.vala (+144/-7)
katze/katze.vapi (+2/-0)
To merge this branch: bzr merge lp:~ivaldi/midori/tabby-tab-order
Reviewer Review Type Date Requested Status
Cris Dywan Approve
Review via email: mp+186165@code.launchpad.net

Commit message

add tab sorting

To post a comment you must log in.
lp:~ivaldi/midori/tabby-tab-order updated
6407. By André Stösel

merge lp:midori

Revision history for this message
Cris Dywan (kalikiana) wrote :

I'm afraid my test run on a large session with carefully opened tabs for testing completely failed. a) The order is at one point reversed b) New tabs end up at the end, not in the real location

review: Needs Fixing
Revision history for this message
André Stösel (ivaldi) wrote :

Hm, strange - works fine for me - can you reproduce it?
What i tested: new session, create some tabs A, B, C, opened new tabs on B (A, B, B1, B2, C) switched tabs and restored sessions multiple times

Maybe you can monitor the databases while creating new tabs?

Revision history for this message
Cris Dywan (kalikiana) wrote :

So I did a more controlled test run: new session, opening tabs via Ctrl+T, "Open in New Tab", opening externally, and closing some. I verified using screenshots that the order is retained across restarts.

So next up will be a) moving tabs b) order of existing sessions (nice to have if not terribly hard)

review: Approve
Revision history for this message
Cris Dywan (kalikiana) wrote :

FTR I didn't see it easily in the commit history but lp:~ivaldi/midori/tabby-tab-usage is already part of this branch.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'data/tabby/Update1.sql'
2--- data/tabby/Update1.sql 1970-01-01 00:00:00 +0000
3+++ data/tabby/Update1.sql 2013-09-28 14:13:48 +0000
4@@ -0,0 +1,4 @@
5+ALTER TABLE tabs ADD sorting REAL DEFAULT 0;
6+
7+CREATE INDEX sorting on tabs (sorting ASC);
8+CREATE INDEX tstamp on tabs (tstamp ASC);
9
10=== modified file 'extensions/tabby.vala'
11--- extensions/tabby.vala 2013-09-26 16:24:19 +0000
12+++ extensions/tabby.vala 2013-09-28 14:13:48 +0000
13@@ -65,18 +65,28 @@
14 }
15
16 public abstract class Session : GLib.Object, ISession {
17+ protected GLib.SList<double?> tab_sorting;
18+
19+ public Midori.Browser browser { get; protected set; }
20+
21 public abstract void add_item (Katze.Item item);
22 public abstract void uri_changed (Midori.View view, string uri);
23 public abstract void data_changed (Midori.View view);
24 public abstract void tab_added (Midori.Browser browser, Midori.View view);
25 public abstract void tab_removed (Midori.Browser browser, Midori.View view);
26- public abstract void close ();
27+ public abstract void tab_switched (Midori.View? old_view, Midori.View? new_view);
28+
29 public abstract Katze.Array get_tabs ();
30
31 public void attach (Midori.Browser browser) {
32- browser.add_tab.connect (this.tab_added);
33+ this.browser = browser;
34+
35+ browser.add_tab.connect_after (this.tab_added);
36 browser.add_tab.connect (this.helper_data_changed);
37+
38 browser.remove_tab.connect (this.tab_removed);
39+ browser.switch_tab.connect (this.tab_switched);
40+ browser.delete_event.connect_after(this.delete_event);
41
42 foreach (Midori.View view in browser.get_tabs ()) {
43 this.tab_added (browser, view);
44@@ -85,6 +95,8 @@
45 }
46
47 public void restore (Midori.Browser browser) {
48+ this.browser = browser;
49+
50 Katze.Array tabs = this.get_tabs ();
51
52 if(tabs.is_empty ()) {
53@@ -93,9 +105,12 @@
54 tabs.add_item (item);
55 }
56
57- browser.add_tab.connect (this.tab_added);
58+ browser.add_tab.connect_after (this.tab_added);
59 browser.add_tab.connect (this.helper_data_changed);
60+
61 browser.remove_tab.connect (this.tab_removed);
62+ browser.switch_tab.connect (this.tab_switched);
63+ browser.delete_event.connect_after(this.delete_event);
64
65 GLib.List<unowned Katze.Item> items = tabs.get_items ();
66 unowned GLib.List<unowned Katze.Item> u_items = items;
67@@ -104,27 +119,87 @@
68
69 GLib.Idle.add (() => {
70 /* Note: we need to use `items` for something to maintain a valid reference */
71+ GLib.PtrArray new_tabs = new GLib.PtrArray ();
72 if (items.length () > 0) {
73 for (int i = 0; i < 3; i++) {
74- if (u_items == null)
75+ if (u_items == null) {
76+ this.helper_reorder_tabs (new_tabs);
77 return false;
78+ }
79
80 Katze.Item t_item = u_items.data<Katze.Item>;
81
82+ t_item.set_meta_integer ("append", 1);
83+
84 if (delay)
85 t_item.set_meta_integer ("delay", Midori.Delay.DELAYED);
86 else
87 delay = true;
88
89- browser.add_item (t_item);
90+ unowned Gtk.Widget tab = browser.add_item (t_item);
91+ new_tabs.add (tab);
92
93 u_items = u_items.next;
94 }
95+ this.helper_reorder_tabs (new_tabs);
96 }
97 return u_items != null;
98 });
99 }
100
101+ public virtual void close () {
102+ this.browser.add_tab.disconnect (this.tab_added);
103+ this.browser.add_tab.disconnect (this.helper_data_changed);
104+ this.browser.remove_tab.disconnect (this.tab_removed);
105+ this.browser.switch_tab.disconnect (this.tab_switched);
106+ this.browser.delete_event.disconnect (this.delete_event);
107+ }
108+
109+#if HAVE_GTK3
110+ protected bool delete_event (Gtk.Widget widget, Gdk.EventAny event) {
111+#else
112+ protected bool delete_event (Gtk.Widget widget, Gdk.Event event) {
113+#endif
114+
115+ this.close();
116+ return false;
117+
118+ }
119+
120+ protected double? get_tab_sorting (Midori.View view) {
121+ int this_pos = this.browser.notebook.page_num (view);
122+ Midori.View prev_view = this.browser.notebook.get_nth_page (this_pos - 1) as Midori.View;
123+ Midori.View next_view = this.browser.notebook.get_nth_page (this_pos + 1) as Midori.View;
124+
125+ string? prev_meta_sorting = null;
126+ string? next_meta_sorting = null;
127+ double? prev_sorting, next_sorting, this_sorting;
128+
129+ if (prev_view != null) {
130+ unowned Katze.Item prev_item = prev_view.get_proxy_item ();
131+ prev_meta_sorting = prev_item.get_meta_string ("sorting");
132+ }
133+
134+ if (prev_meta_sorting == null)
135+ prev_sorting = double.parse ("0");
136+ else
137+ prev_sorting = double.parse (prev_meta_sorting);
138+
139+ if (next_view != null) {
140+ unowned Katze.Item next_item = next_view.get_proxy_item ();
141+ next_meta_sorting = next_item.get_meta_string ("sorting");
142+ }
143+
144+ if (next_meta_sorting == null)
145+ next_sorting = prev_sorting + 2048;
146+ else
147+ next_sorting = double.parse (next_meta_sorting);
148+
149+ this_sorting = prev_sorting + (next_sorting - prev_sorting) / 2;
150+
151+ return this_sorting;
152+ }
153+
154 private void helper_data_changed (Midori.Browser browser, Midori.View view) {
155 ulong sig_id = 0;
156 sig_id = view.web_view.load_started.connect (() => {
157@@ -143,6 +218,42 @@
158 }
159 });
160 }
161+
162+ private void helper_reorder_tabs (GLib.PtrArray new_tabs) {
163+ CompareDataFunc<double?> helper_compare_data = (a, b) => {
164+ if (a > b)
165+ return 1;
166+ else if(a < b)
167+ return -1;
168+ return 0;
169+ };
170+
171+ GLib.CompareFunc<double?> helper_compare_func = (a,b) => {
172+ return a == b ? 0 : -1;
173+ };
174+
175+ for(var i = 0; i < new_tabs.len; i++) {
176+ Midori.View tab = new_tabs.index(i) as Midori.View;
177+
178+ unowned Katze.Item item = tab.get_proxy_item ();
179+
180+ double? sorting;
181+ string? sorting_string = item.get_meta_string ("sorting");
182+ if (sorting_string != null) { /* we have to use a seperate if condition to avoid a `possibly unassigned local variable` error */
183+ if (double.try_parse (item.get_meta_string ("sorting"), out sorting)) {
184+ this.tab_sorting.insert_sorted_with_data (sorting, helper_compare_data);
185+
186+ int index = this.tab_sorting.position (this.tab_sorting.find_custom (sorting, helper_compare_func));
187+
188+ this.browser.notebook.reorder_child (tab, index);
189+ }
190+ }
191+ }
192+ }
193+
194+ construct {
195+ this.tab_sorting = new GLib.SList<double?> ();
196+ }
197 }
198 }
199
200@@ -154,7 +265,8 @@
201
202 public override void add_item (Katze.Item item) {
203 GLib.DateTime time = new DateTime.now_local ();
204- string sqlcmd = "INSERT INTO `tabs` (`crdate`, `tstamp`, `session_id`, `uri`, `title`) VALUES (:tstamp, :tstamp, :session_id, :uri, :title);";
205+ string? sorting = item.get_meta_string ("sorting");
206+ string sqlcmd = "INSERT INTO `tabs` (`crdate`, `tstamp`, `session_id`, `uri`, `title`, `sorting`) VALUES (:tstamp, :tstamp, :session_id, :uri, :title, :sorting);";
207 Sqlite.Statement stmt;
208 if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK)
209 critical (_("Failed to update database: %s"), db.errmsg);
210@@ -162,6 +274,11 @@
211 stmt.bind_int64 (stmt.bind_parameter_index (":session_id"), this.id);
212 stmt.bind_text (stmt.bind_parameter_index (":uri"), item.uri);
213 stmt.bind_text (stmt.bind_parameter_index (":title"), item.name);
214+ if (sorting == null)
215+ stmt.bind_double (stmt.bind_parameter_index (":sorting"), double.parse ("1"));
216+ else
217+ stmt.bind_double (stmt.bind_parameter_index (":sorting"), double.parse (sorting));
218+
219 if (stmt.step () != Sqlite.DONE)
220 critical (_("Failed to update database: %s"), db.errmsg);
221 else {
222@@ -202,6 +319,8 @@
223 unowned Katze.Item item = view.get_proxy_item ();
224 int64 tab_id = item.get_meta_integer ("tabby-id");
225 if (tab_id < 1) {
226+ double? sorting = this.get_tab_sorting (view);
227+ item.set_meta_string ("sorting", sorting.to_string ());
228 this.add_item (item);
229 }
230 }
231@@ -220,7 +339,24 @@
232 critical (_("Failed to update database: %s"), db.errmsg ());
233 }
234
235+ protected override void tab_switched (Midori.View? old_view, Midori.View? new_view) {
236+ GLib.DateTime time = new DateTime.now_local ();
237+ unowned Katze.Item item = new_view.get_proxy_item ();
238+ int64 tab_id = item.get_meta_integer ("tabby-id");
239+ string sqlcmd = "UPDATE `tabs` SET tstamp = :tstamp WHERE session_id = :session_id AND id = :tab_id;";
240+ Sqlite.Statement stmt;
241+ if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK)
242+ critical (_("Failed to update database: %s"), db.errmsg ());
243+ stmt.bind_int64 (stmt.bind_parameter_index (":session_id"), this.id);
244+ stmt.bind_int64 (stmt.bind_parameter_index (":tab_id"), tab_id);
245+ stmt.bind_int64 (stmt.bind_parameter_index (":tstamp"), time.to_unix ());
246+ if (stmt.step () != Sqlite.DONE)
247+ critical (_("Failed to update database: %s"), db.errmsg ());
248+ }
249+
250 public override void close() {
251+ base.close ();
252+
253 if (Session.open_sessions == 1)
254 return;
255
256@@ -239,7 +375,7 @@
257 public override Katze.Array get_tabs() {
258 Katze.Array tabs = new Katze.Array (typeof (Katze.Item));
259
260- string sqlcmd = "SELECT id, uri, title FROM tabs WHERE session_id = :session_id";
261+ string sqlcmd = "SELECT id, uri, title, sorting FROM tabs WHERE session_id = :session_id ORDER BY tstamp DESC";
262 Sqlite.Statement stmt;
263 if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK)
264 critical (_("Failed to select from database: %s"), db.errmsg ());
265@@ -258,6 +394,7 @@
266 item.uri = uri;
267 item.name = title;
268 item.set_meta_integer ("tabby-id", id);
269+ item.set_meta_string ("sorting", stmt.column_double (3).to_string ());
270 tabs.add_item (item);
271 result = stmt.step ();
272 }
273
274=== modified file 'katze/katze.vapi'
275--- katze/katze.vapi 2013-04-26 18:04:35 +0000
276+++ katze/katze.vapi 2013-09-28 14:13:48 +0000
277@@ -33,6 +33,8 @@
278 public bool get_meta_boolean (string key);
279 public int64 get_meta_integer (string key);
280 public void set_meta_integer (string key, int64 value);
281+ public unowned string? get_meta_string (string key);
282+ public void set_meta_string (string key, string value);
283 }
284 }
285

Subscribers

People subscribed via source and target branches

to all changes: