Merge lp:~artem-anufrij/scratch/Bugfix-1222075 into lp:~elementary-apps/scratch/scratch

Proposed by Artem Anufrij
Status: Superseded
Proposed branch: lp:~artem-anufrij/scratch/Bugfix-1222075
Merge into: lp:~elementary-apps/scratch/scratch
Diff against target: 330 lines (+277/-4)
5 files modified
plugins/CMakeLists.txt (+2/-1)
plugins/clipboard-history/CMakeLists.txt (+28/-0)
plugins/clipboard-history/ClipboardHistory.vala (+230/-0)
plugins/clipboard-history/clipboard-history.plugin (+10/-0)
src/Widgets/SourceView.vala (+7/-3)
To merge this branch: bzr merge lp:~artem-anufrij/scratch/Bugfix-1222075
Reviewer Review Type Date Requested Status
Robert Roth Pending
Review via email: mp+241634@code.launchpad.net

This proposal supersedes a proposal from 2014-11-07.

This proposal has been superseded by a proposal from 2014-12-02.

Description of the change

"Clipboard History" was implemented into Scratch.

"Clipboard History" stores all COPY and CUT actions. System-wide.

Please test it and give me your feedback!

To post a comment you must log in.
Revision history for this message
Robert Roth (evfool) wrote : Posted in a previous version of this proposal

On clicking Paste on one of the items from the clipboard history, I get the following in the console :
[_LOG_LEVEL_FATAL 18:44:12.349959] [GLib] g_string_erase: assertion 'pos >= 0' failed
[_LOG_LEVEL_FATAL 18:44:12.350001] Scratch will not function properly.
Other than that, the plugin could be more useful if it would listen for Gtk clipboard changes [1] (currently only text cut/copied from scratch is added)

[1] https://developer.gnome.org/gtk3/stable/gtk3-Clipboards.html

review: Needs Fixing
Revision history for this message
Artem Anufrij (artem-anufrij) wrote : Posted in a previous version of this proposal

Hey Robert,

always when you add a new tab, scratch throws this exeption. It's not a plugin Error.

"[_LOG_LEVEL_FATAL 18:44:12.349959] [GLib] g_string_erase: assertion 'pos >= 0' failed"

> Other than that, the plugin could be more useful if it would listen for Gtk clipboard changes [1] (currently only text cut/copied from scratch is added)

Thanks for the tip! I will implement it!!!

Revision history for this message
Artem Anufrij (artem-anufrij) wrote :

What is still missing in this case?

Revision history for this message
Artem Anufrij (artem-anufrij) wrote :

Clipboard history stores all COPY and CUT actions. System-wide.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/CMakeLists.txt'
2--- plugins/CMakeLists.txt 2014-06-16 22:28:26 +0000
3+++ plugins/CMakeLists.txt 2014-11-12 23:59:09 +0000
4@@ -12,4 +12,5 @@
5 add_subdirectory (source-tree)
6 add_subdirectory (outline)
7 add_subdirectory (vim-emulation)
8-add_subdirectory (highlight-word-selection)
9\ No newline at end of file
10+add_subdirectory (highlight-word-selection)
11+add_subdirectory (clipboard-history)
12\ No newline at end of file
13
14=== added directory 'plugins/clipboard-history'
15=== added file 'plugins/clipboard-history/CMakeLists.txt'
16--- plugins/clipboard-history/CMakeLists.txt 1970-01-01 00:00:00 +0000
17+++ plugins/clipboard-history/CMakeLists.txt 2014-11-12 23:59:09 +0000
18@@ -0,0 +1,28 @@
19+add_definitions(${NORMAL_CFLAGS})
20+include_directories(${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/scratchcore/)
21+link_directories(${NORMAL_LINK_DIRS})
22+
23+vala_precompile(VALA_C
24+ ClipboardHistory.vala
25+PACKAGES
26+ granite
27+ gtksourceview-3.0
28+ scratchcore
29+ gee-0.8
30+ libpeas-1.0
31+ ${ZEITGEIST_DEPS}
32+OPTIONS
33+ --thread
34+ --vapidir=${CMAKE_BINARY_DIR}
35+ --vapidir=${CMAKE_BINARY_DIR}/src/
36+ --vapidir=${CMAKE_SOURCE_DIR}/vapi/
37+ --vapidir=${CMAKE_BINARY_DIR}/scratchcore/
38+)
39+
40+add_library(clipboard-history MODULE ${VALA_C})
41+add_dependencies(clipboard-history scratchcore scratch)
42+
43+install(TARGETS clipboard-history DESTINATION lib/scratch/plugins/clipboard-history/)
44+install(FILES clipboard-history.plugin DESTINATION lib/scratch/plugins/clipboard-history/)
45+
46+message("-- Clipboard History plugin will be compiled")
47\ No newline at end of file
48
49=== added file 'plugins/clipboard-history/ClipboardHistory.vala'
50--- plugins/clipboard-history/ClipboardHistory.vala 1970-01-01 00:00:00 +0000
51+++ plugins/clipboard-history/ClipboardHistory.vala 2014-11-12 23:59:09 +0000
52@@ -0,0 +1,230 @@
53+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
54+/***
55+ BEGIN LICENSE
56+
57+ Copyright (C) 2014 Artem Anufrij <artem.anufrij@live.de>
58+ This program is free software: you can redistribute it and/or modify it
59+ under the terms of the GNU Lesser General Public License version 3, as published
60+ by the Free Software Foundation.
61+
62+ This program is distributed in the hope that it will be useful, but
63+ WITHOUT ANY WARRANTY; without even the implied warranties of
64+ MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
65+ PURPOSE. See the GNU General Public License for more details.
66+
67+ You should have received a copy of the GNU General Public License along
68+ with this program. If not, see <http://www.gnu.org/licenses/>
69+
70+ END LICENSE
71+***/
72+
73+public const string NAME = N_("Clipboard History");
74+public const string DESCRIPTION = N_("Clipboard to view history");
75+
76+public class Scratch.Plugins.ClipboardHistory : Peas.ExtensionBase, Peas.Activatable {
77+
78+ const int MAX_SIZE = 32;
79+ const int MAX_LINE_LENGTH = 24;
80+ const string DOTS = _("...");
81+ MainWindow window = null;
82+ Gtk.Notebook? contextbar = null;
83+
84+ Gtk.ScrolledWindow scrolled;
85+ Gtk.ListStore list_store;
86+ Gtk.TreeIter iter;
87+ Gtk.TreeView view;
88+
89+ Gtk.Menu menu;
90+ Gtk.MenuItem menu_paste;
91+ Gtk.MenuItem menu_delete;
92+
93+ Scratch.Services.Interface plugins;
94+ public Object object { owned get; construct; }
95+
96+ public void update_state () {
97+ }
98+
99+ public void activate () {
100+ debug ("-- %s avtivate", NAME);
101+
102+ plugins = (Scratch.Services.Interface) object;
103+
104+ plugins.hook_window.connect ((w) => {
105+ if(window != null)
106+ return;
107+
108+ window = w;
109+ window.clipboard.owner_change.connect (clipboard_action);
110+ });
111+
112+ plugins.hook_notebook_context.connect ((n) => {
113+ if (contextbar == null) {
114+ this.contextbar = n;
115+
116+ build_plugin_ui ();
117+ }
118+ });
119+ }
120+
121+ public void deactivate () {
122+ debug ("-- %s deavtivate", NAME);
123+
124+ contextbar.remove_page (contextbar.page_num (scrolled));
125+
126+ window.clipboard.owner_change.disconnect (clipboard_action);
127+ }
128+
129+ void clipboard_action(Gdk.Event event) {
130+ string? clipboard_content = window.clipboard.wait_for_text ();
131+ if (clipboard_content != null)
132+ add_clipboard_item (clipboard_content);
133+ }
134+
135+ void add_clipboard_item (string clipboard_content) {
136+ if(clipboard_content == "")
137+ return;
138+
139+ // Set the plugin visible
140+ if (contextbar.page_num (scrolled) == -1)
141+ contextbar.append_page (scrolled, new Gtk.Label (_("Clipboard History")));
142+
143+ // Delete last item, if the size of the list store > MAX_SIZE
144+ if (list_store.get_iter_from_string (out iter, (MAX_SIZE - 1).to_string ()))
145+ list_store.remove (iter);
146+
147+ // Delete dupplicates from list store, if exists
148+ delete_dupplicates (clipboard_content);
149+
150+ // Create a short title
151+ string title = create_clipboard_item_title (clipboard_content);
152+
153+ if (title == "")
154+ return;
155+
156+ // Add a new item
157+ list_store.insert (out iter, 0);
158+ list_store.set (iter, 0, "edit-paste", 1, title, 2, clipboard_content);
159+ }
160+
161+ string create_clipboard_item_title (string clipboard_content) {
162+
163+ string [] lines = clipboard_content.split ("\n");
164+
165+ string title = "";
166+
167+ for (int i = 0; i < lines.length; i++ ){
168+ if (lines [i].strip () != "") {
169+ title = lines [i];
170+ if (i > 0)
171+ title = DOTS + title; // ...Code
172+ if (title.length > MAX_LINE_LENGTH)
173+ title = title.substring (0, MAX_LINE_LENGTH) + DOTS; // Code...
174+ else if (i + 1 < lines.length)
175+ title += DOTS; // Code...
176+ break;
177+ }
178+ }
179+
180+ return title;
181+ }
182+
183+ void delete_dupplicates (string new_clipboard_string) {
184+ Gtk.TreeIter? to_delete = null;
185+ list_store.foreach ((model, path, it) => {
186+ Value content;
187+ list_store.get_value (it, 2, out content);
188+ string clipboard_string = content.get_string ();
189+ if (clipboard_string == new_clipboard_string) {
190+ to_delete = it;
191+ return true;
192+ }
193+
194+ return false;
195+ });
196+
197+ if (to_delete != null)
198+ list_store.remove (to_delete);
199+ }
200+
201+ void build_plugin_ui () {
202+ scrolled = new Gtk.ScrolledWindow (null, null);
203+ list_store = new Gtk.ListStore (3, typeof (string), typeof (string), typeof (string));
204+
205+ // Context Menu
206+ menu = new Gtk.Menu ();
207+
208+ menu_delete = new Gtk.MenuItem.with_label (_("Delete"));
209+ menu_delete.activate.connect (delete_selected);
210+
211+ menu_paste = new Gtk.MenuItem.with_label (_("Paste"));
212+ menu_paste.activate.connect (paste_selected);
213+
214+ menu.append (menu_paste);
215+ menu.append (menu_delete);
216+
217+ menu.show_all ();
218+
219+ // The View
220+ view = new Gtk.TreeView.with_model (list_store);
221+ view.headers_visible = false;
222+ view.set_tooltip_column (2);
223+
224+ view.insert_column_with_attributes (-1, "icon-name", new Gtk.CellRendererPixbuf (), "icon_name", 0);
225+ view.insert_column_with_attributes (-1, "clipboard", new Gtk.CellRendererText (), "text", 1);
226+ view.button_press_event.connect (show_context_menu);
227+
228+ scrolled.add (view);
229+ scrolled.show_all ();
230+ }
231+
232+ public bool show_context_menu (Gtk.Widget sender, Gdk.EventButton evt) {
233+ if (evt.type == Gdk.EventType.BUTTON_PRESS && evt.button == 3)
234+ menu.popup (null, null, null, evt.button, evt.time);
235+
236+ return false;
237+ }
238+
239+ public void paste_selected () {
240+ var selection = view.get_selection();
241+ selection.set_mode(Gtk.SelectionMode.SINGLE);
242+ Gtk.TreeModel model;
243+ Gtk.TreeIter iter;
244+ if (!selection.get_selected(out model, out iter)) {
245+ return;
246+ }
247+ Value content;
248+ model.get_value(iter, 2, out content);
249+ string clipboard_string = content.get_string ();
250+
251+ Scratch.Services.Document? current_document = window.get_current_document ();
252+
253+ if (current_document == null)
254+ return;
255+ // Set focus on active document, delete selected text and paste the value from selected item.
256+ current_document.focus();
257+ current_document.source_view.delete_from_cursor (Gtk.DeleteType.CHARS, current_document.source_view.get_selected_text ().length);
258+ current_document.source_view.insert_at_cursor (clipboard_string);
259+ }
260+
261+ public void delete_selected () {
262+ var selection = view.get_selection();
263+ selection.set_mode(Gtk.SelectionMode.SINGLE);
264+ Gtk.TreeModel model;
265+ Gtk.TreeIter iter;
266+ if (!selection.get_selected(out model, out iter)) {
267+ return;
268+ }
269+ list_store.remove (iter);
270+
271+ // Hiding PlugIn, if no more items exist in the list store.
272+ if (!list_store.get_iter_first (out iter))
273+ contextbar.remove_page (contextbar.page_num (scrolled));
274+ }
275+}
276+
277+[ModuleInit]
278+public void peas_register_types (GLib.TypeModule module) {
279+ var objmodule = module as Peas.ObjectModule;
280+ objmodule.register_extension_type (typeof (Peas.Activatable),
281+ typeof (Scratch.Plugins.ClipboardHistory));
282+}
283\ No newline at end of file
284
285=== added file 'plugins/clipboard-history/clipboard-history.plugin'
286--- plugins/clipboard-history/clipboard-history.plugin 1970-01-01 00:00:00 +0000
287+++ plugins/clipboard-history/clipboard-history.plugin 2014-11-12 23:59:09 +0000
288@@ -0,0 +1,10 @@
289+[Plugin]
290+Module=clipboard-history
291+Loader=C
292+IAge=2
293+Name=Clipboard History
294+Description=Clipboard History
295+Icon=edit-paste
296+Authors=Artem Anufrij <artem.anufrij@live.de>
297+Copyright=Copyright © 2014 Scratch and Artem Anufrij
298+Website=http://launchpad.net/scratch
299\ No newline at end of file
300
301=== modified file 'src/Widgets/SourceView.vala'
302--- src/Widgets/SourceView.vala 2014-10-29 19:28:47 +0000
303+++ src/Widgets/SourceView.vala 2014-11-12 23:59:09 +0000
304@@ -260,11 +260,12 @@
305 }
306
307 // Get selected text
308- public string get_selected_text () {
309+ public string get_selected_text (bool replace_new_line = true) {
310 TextIter start, end;
311 this.buffer.get_selection_bounds (out start, out end);
312 string selected = this.buffer.get_text (start, end, true);
313- selected = selected.chomp ().replace ("\n", " ");
314+ if (replace_new_line)
315+ selected = selected.chomp ().replace ("\n", " ");
316 return selected;
317 }
318
319@@ -306,7 +307,10 @@
320 buffer.place_cursor (start);
321 }
322
323- public void set_language (SourceLanguage lang) {
324+ public void set_language (SourceLanguage? lang) {
325+ if (lang == null)
326+ return;
327+
328 this.buffer.set_language (lang);
329 this.language_changed (lang);
330 }

Subscribers

People subscribed via source and target branches