Merge lp:~ivaldi/midori/tabby-tab-order into lp:midori
- tabby-tab-order
- Merge into trunk
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 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Approve | ||
Review via email:
|
Commit message
add tab sorting
Description of the change
To post a comment you must log in.
- 6407. By André Stösel
-
merge lp:midori
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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 |
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