1// 2// Copyright (C) 2010-2011 Robert Dyer 3// 4// This file is part of Plank. 5// 6// Plank is free software: you can redistribute it and/or modify 7// it under the terms of the GNU General Public License as published by 8// the Free Software Foundation, either version 3 of the License, or 9// (at your option) any later version. 10// 11// Plank is distributed in the hope that it will be useful, 12// but WITHOUT ANY WARRANTY; without even the implied warranty of 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14// GNU General Public License for more details. 15// 16// You should have received a copy of the GNU General Public License 17// along with this program. If not, see <http://www.gnu.org/licenses/>. 18// 19 20using Plank; 21 22namespace Docky 23{ 24 public class ClippyDockItem : DockletItem 25 { 26 Gtk.Clipboard clipboard; 27 Gee.ArrayList<string> clips; 28 int cur_position = 0; 29 ulong handler_id = 0U; 30 31 /** 32 * {@inheritDoc} 33 */ 34 public ClippyDockItem.with_dockitem_file (GLib.File file) 35 { 36 GLib.Object (Prefs: new ClippyPreferences.with_file (file)); 37 } 38 39 construct 40 { 41 unowned ClippyPreferences prefs = (ClippyPreferences) Prefs; 42 43 Icon = "edit-cut"; 44 45 if (prefs.TrackMouseSelections) 46 clipboard = Gtk.Clipboard.get (Gdk.Atom.intern ("PRIMARY", true)); 47 else 48 clipboard = Gtk.Clipboard.get (Gdk.Atom.intern ("CLIPBOARD", true)); 49 50 clips = new Gee.ArrayList<string> (); 51 handler_id = clipboard.owner_change.connect (check_clipboard); 52 53 updated (); 54 } 55 56 ~ClippyDockItem () 57 { 58 if (handler_id > 0U) 59 clipboard.disconnect (handler_id); 60 } 61 62 [CCode (instance_pos = -1)] 63 void check_clipboard (Gtk.Clipboard clipboard, Gdk.Event event) 64 { 65 clipboard.request_text ((Gtk.ClipboardTextReceivedFunc) clipboard_text_received); 66 } 67 68 [CCode (instance_pos = -1)] 69 void clipboard_text_received (Gtk.Clipboard clipboard, string? text) 70 { 71 if (text == null || text == "") 72 return; 73 74 unowned ClippyPreferences prefs = (ClippyPreferences) Prefs; 75 76 clips.remove (text); 77 clips.add (text); 78 while (clips.size > prefs.MaxEntries) 79 clips.remove_at (0); 80 81 cur_position = clips.size; 82 83 updated (); 84 } 85 86 void updated () 87 { 88 if (clips.size == 0) 89 Text = _("Clipboard is currently empty."); 90 else if (cur_position == 0 || cur_position > clips.size) 91 Text = get_entry_at (clips.size); 92 else 93 Text = get_entry_at (cur_position); 94 } 95 96 string get_entry_at (int pos) 97 { 98 return clips.get (pos - 1).replace ("\n", "").replace ("\t", ""); 99 } 100 101 void copy_entry_at (int pos) 102 { 103 if (pos < 1 || pos > clips.size) 104 return; 105 106 var str = clips.get (pos - 1); 107 clipboard.set_text (str, (int) str.length); 108 109 updated (); 110 } 111 112 void copy_entry () 113 { 114 if (cur_position == 0) 115 copy_entry_at (clips.size); 116 else 117 copy_entry_at (cur_position); 118 } 119 120 void clear () 121 { 122 // Make sure we own the current clipboard content, 123 // so we are allowed to clear it 124 clipboard.set_text ("", 0); 125 126 clipboard.clear (); 127 clips.clear (); 128 cur_position = 0; 129 130 updated (); 131 } 132 133 protected override AnimationType on_scrolled (Gdk.ScrollDirection direction, Gdk.ModifierType mod, uint32 event_time) 134 { 135 if (direction == Gdk.ScrollDirection.UP) 136 cur_position++; 137 else 138 cur_position--; 139 140 if (cur_position < 1) 141 cur_position = clips.size; 142 else if (cur_position > clips.size) 143 cur_position = 1; 144 145 updated (); 146 147 return AnimationType.NONE; 148 } 149 150 protected override AnimationType on_clicked (PopupButton button, Gdk.ModifierType mod, uint32 event_time) 151 { 152 if (button == PopupButton.LEFT && clips.size > 0) { 153 copy_entry (); 154 return AnimationType.BOUNCE; 155 } 156 157 return AnimationType.NONE; 158 } 159 160 public override Gee.ArrayList<Gtk.MenuItem> get_menu_items () 161 { 162 var items = new Gee.ArrayList<Gtk.MenuItem> (); 163 164 for (var i = clips.size ; i > 0; i--) { 165 var item = create_literal_menu_item (clips.get (i - 1), "edit-cut"); 166 var pos = i; 167 item.activate.connect (() => { 168 copy_entry_at (pos); 169 }); 170 items.add (item); 171 } 172 173 if (clips.size > 0) { 174 var item = create_menu_item (_("_Clear"), "edit-clear-all", true); 175 item.activate.connect (clear); 176 items.add (item); 177 } 178 179 return items; 180 } 181 } 182} 183