Advertisement
rotrevrep

Gtk FileSourceView

Feb 1st, 2016
1,166
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. namespace Gtk {
  2.     public class FileSourceBar : Gtk.Revealer {
  3.         Gtk.InfoBar info_bar;
  4.         Gtk.Label label;
  5.         Gtk.Image image;
  6.        
  7.         construct {
  8.             info_bar = new Gtk.InfoBar();
  9.             info_bar.response.connect (id => {
  10.                 set_reveal_child (false);
  11.                 response (id);
  12.             });
  13.             info_bar.add_buttons ("OK", Gtk.ResponseType.OK, "Cancel", Gtk.ResponseType.CANCEL);
  14.             label = new Gtk.Label ("");
  15.             image = new Gtk.Image.from_icon_name ("dialog-warning", Gtk.IconSize.LARGE_TOOLBAR);
  16.             var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 5);
  17.             box.pack_start (image, false, false);
  18.             box.pack_start (label);
  19.             info_bar.get_content_area().add (box);
  20.             add (info_bar);
  21.            
  22.             notify["message"].connect (() => {
  23.                 label.label = message;
  24.             });
  25.             notify["message-type"].connect (() => {
  26.                 info_bar.message_type = message_type;
  27.                 if (message_type == Gtk.MessageType.INFO)
  28.                     image.icon_name = "dialog-information";
  29.                 if (message_type == Gtk.MessageType.WARNING)
  30.                     image.icon_name = "dialog-warning";
  31.                 if (message_type == Gtk.MessageType.QUESTION)
  32.                     image.icon_name = "dialog-question";
  33.                 if (message_type == Gtk.MessageType.ERROR)
  34.                     image.icon_name = "dialog-error";
  35.             });
  36.         }
  37.        
  38.         public signal void response (int id);
  39.        
  40.         public string message { get; set; }
  41.         public Gtk.MessageType message_type { get; set; }
  42.     }
  43.    
  44.     public class Search : Gtk.Revealer {
  45.         Gtk.SearchEntry entry;
  46.        
  47.         construct {
  48.             var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
  49.             entry = new Gtk.SearchEntry();
  50.             entry.key_press_event.connect (event => {
  51.                 if ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0 && event.keyval == Gdk.Key.n)
  52.                     next();
  53.                 if ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0 && event.keyval == Gdk.Key.p)
  54.                     previous();
  55.                 return false;
  56.             });
  57.             entry.changed.connect (() => {
  58.                 text = entry.text;
  59.                 search_changed (text);
  60.             });
  61.             box.pack_start (entry);
  62.             var button = new Gtk.Button.from_icon_name ("dialog-close", Gtk.IconSize.BUTTON);
  63.             button.clicked.connect (() => {
  64.                 set_reveal_child (false);
  65.                 search_canceled();
  66.             });
  67.             var previous_button = new Gtk.Button.from_icon_name ("go-previous", Gtk.IconSize.BUTTON);
  68.             previous_button.clicked.connect (() => { previous(); });
  69.             var next_button = new Gtk.Button.from_icon_name ("go-next", Gtk.IconSize.BUTTON);
  70.             next_button.clicked.connect (() => { next(); });
  71.             box.pack_start (previous_button, false, false);
  72.             box.pack_start (next_button, false, false);
  73.             box.pack_end (button, false, false);
  74.             add (box);
  75.         }
  76.        
  77.         internal int count;
  78.        
  79.         public string text { get; private set; }
  80.        
  81.         public void search() {
  82.             entry.grab_focus();
  83.             set_reveal_child (true);
  84.         }
  85.        
  86.         public signal void next();
  87.         public signal void previous();
  88.        
  89.         public signal void search_canceled();
  90.        
  91.         public signal void search_changed (string text);
  92.     }
  93.    
  94.     public class FileSourceView : Gtk.EventBox {
  95.         GLib.File file;
  96.         GLib.FileMonitor monitor;
  97.         string etag;
  98.         Gtk.TextTag search_tag;
  99.        
  100.         public FileSourceView (string location) {
  101.             GLib.Object (location: location);
  102.         }
  103.        
  104.         construct {
  105.             file = File.new_for_path (location);
  106.             monitor = file.monitor (FileMonitorFlags.NONE);
  107.             var manager = new Gtk.SourceLanguageManager();
  108.             var language = manager.guess_language (location, null);
  109.             if (language == null) {
  110.                 string ext = location.substring (1 + location.index_of ("."));
  111.                 language = manager.get_language (ext);
  112.             }
  113.             buffer = new Gtk.SourceBuffer.with_language (language);
  114.             view = new Gtk.SourceView.with_buffer (buffer);
  115.             var sw = new Gtk.ScrolledWindow (null, null);
  116.             sw.add (view);
  117.            
  118.             var search_bar = new Search();
  119.            
  120.             search_tag = buffer.create_tag ("search-tag", "background", "#C0C0C0", "foreground", "#FFFFFF");
  121.            
  122.             search_bar.search_canceled.connect (() => {
  123.                 Gtk.TextIter start, end;
  124.                 buffer.get_start_iter (out start);
  125.                 buffer.get_end_iter (out end);
  126.                 buffer.remove_tag_by_name ("search-tag", start, end);
  127.             });
  128.            
  129.             search_bar.search_changed.connect (query => {
  130.                 search_bar.count = 0;
  131.                 Gtk.TextIter start, end, start_match, end_match;
  132.                 buffer.get_start_iter (out start);
  133.                 buffer.get_end_iter (out end);
  134.                 buffer.remove_tag_by_name ("search-tag", start, end);
  135.                 while (start.forward_search (query, Gtk.TextSearchFlags.TEXT_ONLY | Gtk.TextSearchFlags.VISIBLE_ONLY,
  136.                 out start_match, out end_match, null)) {
  137.                     search_bar.count++;
  138.                     buffer.apply_tag_by_name ("search-tag", start_match, end_match);
  139.                     int offset = end_match.get_offset();
  140.                     buffer.get_iter_at_offset (out start, offset);
  141.                 }
  142.             });
  143.            
  144.             search_bar.next.connect (() => {
  145.                 Gtk.TextIter start, start_match, end_match;
  146.                 buffer.get_start_iter (out start);
  147.                 if (buffer.get_mark ("last-search-position") != null)
  148.                     buffer.get_iter_at_mark (out start, buffer.get_mark ("last-search-position"));
  149.                 if (start.forward_search (search_bar.text, Gtk.TextSearchFlags.TEXT_ONLY | Gtk.TextSearchFlags.VISIBLE_ONLY,
  150.                 out start_match, out end_match, null)) {
  151.                     buffer.select_range (start_match, end_match);
  152.                     buffer.create_mark ("last-search-position", end_match, false);
  153.                 }
  154.                 else {
  155.                     buffer.get_start_iter (out start);
  156.                     buffer.create_mark ("last-search-position", start, false);
  157.                 }
  158.             });
  159.            
  160.             search_bar.previous.connect (() => {
  161.                 Gtk.TextIter end, start_match, end_match;
  162.                 buffer.get_end_iter (out end);
  163.                 if (buffer.get_mark ("last-search-position") != null)
  164.                     buffer.get_iter_at_mark (out end, buffer.get_mark ("last-search-position"));
  165.                 if (end.backward_search (search_bar.text, Gtk.TextSearchFlags.TEXT_ONLY | Gtk.TextSearchFlags.VISIBLE_ONLY,
  166.                 out start_match, out end_match, null)) {
  167.                     buffer.select_range (start_match, end_match);
  168.                     buffer.create_mark ("last-search-position", start_match, false);
  169.                 }
  170.                 else {
  171.                     buffer.get_start_iter (out end);
  172.                     buffer.create_mark ("last-search-position", end, false);
  173.                 }
  174.             });
  175.            
  176.             bar = new FileSourceBar();
  177.             bar.response.connect (id => {
  178.                 if (id == Gtk.ResponseType.OK && bar.message_type == Gtk.MessageType.INFO) {
  179.                     uint8[] data;
  180.                     file.load_contents (null, out data, null);
  181.                     view.buffer.text = (string)data;
  182.                     saved();
  183.                 }
  184.                 else if (id == Gtk.ResponseType.OK && bar.message_type == Gtk.MessageType.WARNING) {
  185.                     string tag;
  186.                     file.replace_contents (view.buffer.text.data, etag, true, FileCreateFlags.NONE, out tag);
  187.                     etag = tag;
  188.                 }
  189.             });
  190.            
  191.             bool changed = false;
  192.             monitor.changed.connect ((f1, f2, event_type) => {
  193.                 if (event_type == FileMonitorEvent.CHANGES_DONE_HINT) {
  194.                     if (changed) {
  195.                         changed = false;
  196.                         return;
  197.                     }
  198.                     bar.message_type = Gtk.MessageType.INFO;
  199.                     bar.message = "file content changed. reload it ?";
  200.                     bar.reveal_child = true;
  201.                 }
  202.                 if (f1.get_path() == location && event_type == FileMonitorEvent.DELETED) {
  203.                     bar.message_type = Gtk.MessageType.WARNING;
  204.                     bar.message = "file deleted. save it ?";
  205.                     bar.reveal_child = true;
  206.                     changed = true;
  207.                 }
  208.             });
  209.            
  210.             var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
  211.             box.pack_start (bar, false, false);
  212.             box.pack_start (search_bar, false, false);
  213.             box.pack_start (sw);
  214.             bar.show_all();
  215.             add (box);
  216.            
  217.             realize.connect (() => {
  218.                 uint8[] data;
  219.                 file.load_contents (null, out data, null);
  220.                 view.buffer.text = (string)data;
  221.             });
  222.            
  223.             view.key_press_event.connect (event => {
  224.                 Gtk.TextIter iter;
  225.                 view.buffer.get_iter_at_mark (out iter, view.buffer.get_insert());
  226.                 current_line = iter.get_line();
  227.                 current_column = iter.get_line_offset();
  228.                
  229.                 if ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0 && event.keyval == Gdk.Key.s) {
  230.                     string tag;
  231.                     changed = true;
  232.                     file.replace_contents (view.buffer.text.data, etag, true, FileCreateFlags.NONE, out tag);
  233.                     etag = tag;
  234.                     saved();
  235.                 }
  236.                 if ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0 && event.keyval == Gdk.Key.f) {
  237.                     search_bar.search();
  238.                 }
  239.                 if ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0 && event.keyval == Gdk.Key.n)
  240.                     search_bar.next();
  241.                 if ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0 && event.keyval == Gdk.Key.p)
  242.                     search_bar.previous();
  243.                 return false;
  244.             });
  245.         }
  246.        
  247.         public void add_completion_provider (Gtk.SourceCompletionProvider provider) {
  248.             view.completion.add_provider (provider);
  249.         }
  250.        
  251.         public string get_current_text (Gtk.TextIter iter) {
  252.             Gtk.TextIter start;
  253.             view.buffer.get_iter_at_line_offset (out start, iter.get_line(), 0);
  254.             return start.get_text (iter);
  255.         }
  256.        
  257.         public signal void saved();
  258.        
  259.         public FileSourceBar bar { get; private set; }
  260.         public int current_line { get; private set; }
  261.         public int current_column { get; private set; }
  262.         public string location { get; construct; }
  263.         public Gtk.SourceBuffer buffer { get; private set; }
  264.         public Gtk.SourceView view { get; private set; }
  265.     }
  266. }
Advertisement
RAW Paste Data Copied
Advertisement