add "revert" button to lua script window
[ardour.git] / gtk2_ardour / luawindow.cc
1 /*
2     Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef PLATFORM_WINDOWS
21 #define random() rand()
22 #endif
23
24 #ifdef WAF_BUILD
25 #include "gtk2ardour-config.h"
26 #endif
27
28 #include <glibmm/fileutils.h>
29 #include <gtkmm/messagedialog.h>
30
31 #include "pbd/basename.h"
32 #include "pbd/file_utils.h"
33 #include "pbd/md5.h"
34
35 #include "gtkmm2ext/gtk_ui.h"
36 #include "gtkmm2ext/utils.h"
37 #include "gtkmm2ext/window_title.h"
38
39 #include "ardour/luabindings.h"
40 #include "LuaBridge/LuaBridge.h"
41
42 #include "ardour_ui.h"
43 #include "gui_thread.h"
44 #include "luainstance.h"
45 #include "luawindow.h"
46 #include "public_editor.h"
47 #include "tooltips.h"
48 #include "utils.h"
49 #include "utils_videotl.h"
50
51 #include "i18n.h"
52
53 using namespace ARDOUR;
54 using namespace ARDOUR_UI_UTILS;
55 using namespace PBD;
56 using namespace Gtk;
57 using namespace Glib;
58 using namespace Gtkmm2ext;
59 using namespace std;
60
61
62 inline LuaWindow::BufferFlags operator| (const LuaWindow::BufferFlags& a, const LuaWindow::BufferFlags& b) {
63         return static_cast<LuaWindow::BufferFlags> (static_cast <int>(a) | static_cast<int> (b));
64 }
65
66 inline LuaWindow::BufferFlags operator|= (LuaWindow::BufferFlags& a, const LuaWindow::BufferFlags& b) {
67         return a = static_cast<LuaWindow::BufferFlags> (static_cast <int>(a) | static_cast<int> (b));
68 }
69
70 inline LuaWindow::BufferFlags operator&= (LuaWindow::BufferFlags& a, const LuaWindow::BufferFlags& b) {
71         return a = static_cast<LuaWindow::BufferFlags> (static_cast <int>(a) & static_cast<int> (b));
72 }
73
74 LuaWindow* LuaWindow::_instance = 0;
75
76 LuaWindow*
77 LuaWindow::instance ()
78 {
79         if (!_instance) {
80                 _instance  = new LuaWindow;
81         }
82
83         return _instance;
84 }
85
86 LuaWindow::LuaWindow ()
87         : Window (Gtk::WINDOW_TOPLEVEL)
88         , VisibilityTracker (*((Gtk::Window*) this))
89         , lua (0)
90         , _visible (false)
91         , _menu_scratch (0)
92         , _menu_snippet (0)
93         , _menu_actions (0)
94         , _btn_run (_("Run"))
95         , _btn_clear (_("Clear Outtput"))
96         , _btn_open (_("Import"))
97         , _btn_save (_("Save"))
98         , _btn_delete (_("Delete"))
99         , _btn_revert (_("Revert"))
100         , _current_buffer ()
101 {
102         set_name ("Lua");
103
104         reinit_lua ();
105         update_title ();
106         set_wmclass (X_("ardour_mixer"), PROGRAM_NAME);
107
108         script_select.disable_scrolling ();
109
110         set_border_width (0);
111
112         outtext.set_editable (false);
113         outtext.set_wrap_mode (Gtk::WRAP_WORD);
114         outtext.set_cursor_visible (false);
115
116         signal_delete_event().connect (sigc::mem_fun (*this, &LuaWindow::hide_window));
117         signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
118
119         _btn_run.signal_clicked.connect (sigc::mem_fun(*this, &LuaWindow::run_script));
120         _btn_clear.signal_clicked.connect (sigc::mem_fun(*this, &LuaWindow::clear_output));
121         _btn_open.signal_clicked.connect (sigc::mem_fun(*this, &LuaWindow::import_script));
122         _btn_save.signal_clicked.connect (sigc::mem_fun(*this, &LuaWindow::save_script));
123         _btn_delete.signal_clicked.connect (sigc::mem_fun(*this, &LuaWindow::delete_script));
124         _btn_revert.signal_clicked.connect (sigc::mem_fun(*this, &LuaWindow::revert_script));
125
126         _btn_open.set_sensitive (false); // TODO
127         _btn_save.set_sensitive (false);
128         _btn_delete.set_sensitive (false);
129         _btn_revert.set_sensitive (false);
130
131         // layout
132
133         Gtk::ScrolledWindow *scrollin = manage (new Gtk::ScrolledWindow);
134         scrollin->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
135         scrollin->add (entry);
136         scrollout.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
137         scrollout.add (outtext);
138
139         entry.set_name ("ArdourLuaEntry");
140         outtext.set_name ("ArdourLuaEntry");
141
142         Gtk::HBox *hbox = manage (new HBox());
143
144         hbox->pack_start (_btn_run, false, false, 2);
145         hbox->pack_start (_btn_clear, false, false, 2);
146         hbox->pack_start (_btn_open, false, false, 2);
147         hbox->pack_start (_btn_save, false, false, 2);
148         hbox->pack_start (_btn_delete, false, false, 2);
149         hbox->pack_start (_btn_revert, false, false, 2);
150         hbox->pack_start (script_select, false, false, 2);
151
152         Gtk::VBox *vbox = manage (new VBox());
153         vbox->pack_start (*scrollin, true, true, 0);
154         vbox->pack_start (*hbox, false, false, 2);
155
156         Gtk::VPaned *vpane = manage (new Gtk::VPaned ());
157         vpane->pack1 (*vbox, true, false);
158         vpane->pack2 (scrollout, false, true);
159
160         vpane->show_all ();
161         add (*vpane);
162         set_size_request (640, 480); // XXX
163         ARDOUR_UI_UTILS::set_tooltip (script_select, _("Select Editor Buffer"));
164
165         setup_buffers ();
166         LuaScripting::instance().scripts_changed.connect (*this, invalidator (*this), boost::bind (&LuaWindow::refresh_scriptlist, this), gui_context());
167
168         Glib::RefPtr<Gtk::TextBuffer> tb (entry.get_buffer());
169         _script_changed_connection = tb->signal_changed().connect (sigc::mem_fun(*this, &LuaWindow::script_changed));
170 }
171
172 LuaWindow::~LuaWindow ()
173 {
174         delete lua;
175 }
176
177 void
178 LuaWindow::show_window ()
179 {
180         present();
181         _visible = true;
182 }
183
184 bool
185 LuaWindow::hide_window (GdkEventAny *ev)
186 {
187         if (!_visible) return 0;
188         _visible = false;
189         return just_hide_it (ev, static_cast<Gtk::Window *>(this));
190 }
191
192 void LuaWindow::reinit_lua ()
193 {
194         delete lua;
195         lua = new LuaState();
196         lua->Print.connect (sigc::mem_fun (*this, &LuaWindow::append_text));
197
198         lua_State* L = lua->getState();
199         LuaInstance::register_classes (L);
200         luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
201         lua_setglobal (L, "Editor");
202 }
203
204 void LuaWindow::set_session (Session* s)
205 {
206         SessionHandlePtr::set_session (s);
207         if (!_session) {
208                 return;
209         }
210
211         update_title ();
212         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&LuaWindow::update_title, this), gui_context());
213
214         lua_State* L = lua->getState();
215         LuaBindings::set_session (L, _session);
216 }
217
218 void
219 LuaWindow::session_going_away ()
220 {
221         ENSURE_GUI_THREAD (*this, &LuaWindow::session_going_away);
222         reinit_lua (); // drop state (all variables, session references)
223
224         SessionHandlePtr::session_going_away ();
225         _session = 0;
226         update_title ();
227
228         lua_State* L = lua->getState();
229         LuaBindings::set_session (L, _session);
230 }
231
232 void
233 LuaWindow::update_title ()
234 {
235         if (_session) {
236                 string n;
237
238                 if (_session->snap_name() != _session->name()) {
239                         n = _session->snap_name ();
240                 } else {
241                         n = _session->name ();
242                 }
243
244                 if (_session->dirty ()) {
245                         n = "*" + n;
246                 }
247
248                 WindowTitle title (n);
249                 title += S_("Window|Lua");
250                 title += Glib::get_application_name ();
251                 set_title (title.get_string());
252
253         } else {
254                 WindowTitle title (S_("Window|Lua"));
255                 title += Glib::get_application_name ();
256                 set_title (title.get_string());
257         }
258 }
259
260 void
261 LuaWindow::scroll_to_bottom ()
262 {
263         Gtk::Adjustment *adj;
264         adj = scrollout.get_vadjustment();
265         adj->set_value (MAX(0,(adj->get_upper() - adj->get_page_size())));
266 }
267
268 void
269 LuaWindow::run_script ()
270 {
271         Glib::RefPtr<Gtk::TextBuffer> tb (entry.get_buffer());
272         std::string script = tb->get_text();
273         const std::string& bytecode = LuaScripting::get_factory_bytecode (script);
274         if (bytecode.empty()) {
275                 // plain script or faulty script -- run directly
276                 try {
277                         lua->do_command ("function ardour () end");
278                         if (0 == lua->do_command (script)) {
279                                 append_text ("> OK");
280                         }
281                 } catch (luabridge::LuaException const& e) {
282                         append_text (string_compose (_("LuaException: %1"), e.what()));
283                 }
284         } else {
285                 // script with factory method
286                 try {
287                         lua_State* L = lua->getState();
288                         lua->do_command ("function ardour () end");
289
290                         LuaScriptParamList args = LuaScriptParams::script_params (script, "action_param", false);
291                         luabridge::LuaRef tbl_arg (luabridge::newTable(L));
292                         LuaScriptParams::params_to_ref (&tbl_arg, args);
293                         lua->do_command (script); // register "factory"
294                         luabridge::LuaRef lua_factory = luabridge::getGlobal (L, "factory");
295                         if (lua_factory.isFunction()) {
296                                 lua_factory(tbl_arg)();
297                         }
298                         lua->do_command ("factory = nil;");
299                 } catch (luabridge::LuaException const& e) {
300                         append_text (string_compose (_("LuaException: %1"), e.what()));
301                 }
302         }
303 }
304
305 void
306 LuaWindow::append_text (std::string s)
307 {
308         Glib::RefPtr<Gtk::TextBuffer> tb (outtext.get_buffer());
309         tb->insert (tb->end(), s + "\n");
310         scroll_to_bottom ();
311 }
312
313 void
314 LuaWindow::clear_output ()
315 {
316         Glib::RefPtr<Gtk::TextBuffer> tb (outtext.get_buffer());
317         tb->set_text ("");
318 }
319
320 void
321 LuaWindow::new_script ()
322 {
323         char buf[32];
324         snprintf (buf, sizeof (buf), "#%d", count_scratch_buffers () + 1);
325         script_buffers.push_back (ScriptBufferPtr (new LuaWindow::ScriptBuffer (buf)));
326         script_selection_changed (script_buffers.back ());
327         refresh_scriptlist ();
328 }
329
330 void
331 LuaWindow::delete_script ()
332 {
333         assert (_current_buffer->flags & Buffer_Scratch);
334         for (ScriptBufferList::iterator i = script_buffers.begin (); i != script_buffers.end (); ++i) {
335                 if ((*i) == _current_buffer) {
336                         script_buffers.erase (i);
337                         break;
338                 }
339         }
340
341         for (ScriptBufferList::const_iterator i = script_buffers.begin (); i != script_buffers.end (); ++i) {
342                 if ((*i)->flags & Buffer_Scratch) {
343                         script_selection_changed (*i);
344                         return;
345                 }
346         }
347         new_script ();
348 }
349
350 void
351 LuaWindow::revert_script ()
352 {
353         _current_buffer->flags &= BufferFlags(~Buffer_Valid);
354         script_selection_changed (_current_buffer, true);
355 }
356
357 void
358 LuaWindow::import_script ()
359 {
360         // TODO: dialog to select file or enter URL
361         // TODO convert a few URL (eg. pastebin) to raw.
362 #if 0
363         char *url = "http://pastebin.com/raw/3UMkZ6nV";
364         char *rv = a3_curl_http_get (url, 0);
365         if (rv) {
366                 new_script ();
367                 Glib::RefPtr<Gtk::TextBuffer> tb (entry.get_buffer());
368                 tb->set_text (rv);
369                 _current_buffer->flags &= BufferFlags(~Buffer_Dirty);
370                 update_gui_state ();
371         }
372         free (rv);
373 #endif
374 }
375
376 void
377 LuaWindow::save_script ()
378 {
379         Glib::RefPtr<Gtk::TextBuffer> tb (entry.get_buffer());
380         std::string script = tb->get_text();
381         std::string msg = "Unknown error";
382
383         std::string path;
384         LuaScriptInfoPtr lsi = LuaScripting::script_info (script);
385         ScriptBuffer & sb (*_current_buffer);
386
387         assert (sb.flags & Buffer_Dirty);
388
389         // 1) check if it has a valid header and factory
390         const std::string& bytecode = LuaScripting::get_factory_bytecode (script);
391         if (bytecode.empty()) {
392                 msg = _("Missing script header.\nThe script requires an '{ardour}' info table and a 'factory' function.");
393                 goto errorout;
394         }
395
396         if (!LuaScripting::try_compile (script, LuaScriptParams::script_params (script, "action_param", false))) {
397                 msg = _("Script fails to compile.");
398                 goto errorout;
399         }
400
401         // 2) check script name & type
402         lsi = LuaScripting::script_info (script);
403         if (!lsi) {
404                 msg = _("Invalid or missing script-name or script-type.");
405                 goto errorout;
406         }
407
408         if (lsi->type != LuaScriptInfo::Snippet && lsi->type != LuaScriptInfo::EditorAction) {
409                 msg = _("Invalid script-type.\nValid types are 'EditorAction' and 'Snippet'.");
410                 goto errorout;
411         }
412
413         // 3) if there's already a writable file,...
414         if ((sb.flags & Buffer_HasFile) && !(sb.flags & Buffer_ReadOnly)) {
415                 try {
416                         Glib::file_set_contents (sb.path, script);
417                         sb.flags &= BufferFlags(~Buffer_Dirty);
418                         update_gui_state (); // XXX here?
419                         append_text (X_("> ") + string_compose (_("Saved as %1"), sb.path));
420                         return; // OK
421                 } catch (Glib::FileError e) {
422                         msg = string_compose (_("Error saving file: %1"), e.what());
423                         goto errorout;
424                 }
425         }
426
427         // 4) check if the name is unique for the given type; locally at least
428         if (true /*sb.flags & Buffer_HasFile*/) {
429                 LuaScriptList& lsl (LuaScripting::instance ().scripts (lsi->type));
430                 for (LuaScriptList::const_iterator s = lsl.begin(); s != lsl.end(); ++s) {
431                         if ((*s)->name == lsi->name) {
432                                 msg = string_compose (_("Script with given name '%1' already exists.\nUse a different name in the descriptor."), lsi->name);
433                                 goto errorout;
434                         }
435                 }
436         }
437
438         // 5) construct filename -- TODO ask user for name, ask to replace file.
439         do {
440                 char buf[80];
441                 time_t t = time(0);
442                 struct tm * timeinfo = localtime (&t);
443                 strftime (buf, sizeof(buf), "%s%d", timeinfo);
444                 sprintf (buf, "%s%ld", buf, random ()); // is this valid?
445                 MD5 md5;
446                 std::string fn = md5.digestString (buf);
447
448                 switch (lsi->type) {
449                         case LuaScriptInfo::EditorAction:
450                                 fn = "a_" + fn;
451                                 break;
452                         case LuaScriptInfo::Snippet:
453                                 fn = "s_" + fn;
454                                 break;
455                         default:
456                                 break;
457                 }
458                 path = Glib::build_filename (LuaScripting::user_script_dir (), fn.substr(0, 11) + ".lua");
459         } while (Glib::file_test (path, Glib::FILE_TEST_EXISTS));
460
461         try {
462                 Glib::file_set_contents (path, script);
463                 sb.path = path;
464                 sb.flags |= Buffer_HasFile;
465                 sb.flags &= BufferFlags(~Buffer_Dirty);
466                 update_gui_state (); // XXX here?
467                 LuaScripting::instance().refresh (true);
468                 append_text (X_("> ") + string_compose (_("Saved as %1"), path));
469                 return; // OK
470         } catch (Glib::FileError e) {
471                 msg = string_compose (_("Error saving file: %1"), e.what());
472                 goto errorout;
473         }
474
475 errorout:
476                 MessageDialog am (msg);
477                 am.run ();
478 }
479
480 void
481 LuaWindow::setup_buffers ()
482 {
483         if (script_buffers.size() > 0) {
484                 return;
485         }
486         script_buffers.push_back (ScriptBufferPtr (new LuaWindow::ScriptBuffer("#1")));
487         _current_buffer = script_buffers.front();
488
489         Glib::RefPtr<Gtk::TextBuffer> tb (entry.get_buffer());
490         tb->set_text (_current_buffer->script);
491
492         refresh_scriptlist ();
493         update_gui_state ();
494 }
495
496 uint32_t
497 LuaWindow::count_scratch_buffers () const
498 {
499         uint32_t n = 0;
500         for (ScriptBufferList::const_iterator i = script_buffers.begin (); i != script_buffers.end (); ++i) {
501                 if ((*i)->flags & Buffer_Scratch) {
502                         ++n;
503                 }
504         }
505         return n;
506 }
507
508 void
509 LuaWindow::refresh_scriptlist ()
510 {
511         for (ScriptBufferList::iterator i = script_buffers.begin (); i != script_buffers.end ();) {
512                 if ((*i)->flags & Buffer_Scratch) {
513                         ++i;
514                         continue;
515                 }
516                 i = script_buffers.erase (i);
517         }
518         LuaScriptList& lsa (LuaScripting::instance ().scripts (LuaScriptInfo::EditorAction));
519         for (LuaScriptList::const_iterator s = lsa.begin(); s != lsa.end(); ++s) {
520                 script_buffers.push_back (ScriptBufferPtr ( new LuaWindow::ScriptBuffer(*s)));
521         }
522
523         LuaScriptList& lss (LuaScripting::instance ().scripts (LuaScriptInfo::Snippet));
524         for (LuaScriptList::const_iterator s = lss.begin(); s != lss.end(); ++s) {
525                 script_buffers.push_back (ScriptBufferPtr ( new LuaWindow::ScriptBuffer(*s)));
526         }
527         rebuild_menu ();
528 }
529
530 void
531 LuaWindow::rebuild_menu ()
532 {
533         using namespace Menu_Helpers;
534
535         _menu_scratch = manage (new Menu);
536         _menu_snippet = manage (new Menu);
537         _menu_actions = manage (new Menu);
538
539         MenuList& items_scratch (_menu_scratch->items());
540         MenuList& items_snippet (_menu_snippet->items());
541         MenuList& items_actions (_menu_actions->items());
542
543         {
544                 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(_("New"),
545                                 sigc::mem_fun(*this, &LuaWindow::new_script));
546                 items_scratch.push_back(elem);
547         }
548
549         for (ScriptBufferList::const_iterator i = script_buffers.begin (); i != script_buffers.end (); ++i) {
550                 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem((*i)->name,
551                                 sigc::bind(sigc::mem_fun(*this, &LuaWindow::script_selection_changed), (*i), false));
552
553                 if ((*i)->flags & Buffer_Scratch) {
554                         items_scratch.push_back(elem);
555                 }
556                 else if ((*i)->type == LuaScriptInfo::EditorAction) {
557                                 items_actions.push_back(elem);
558                 }
559                 else if ((*i)->type == LuaScriptInfo::Snippet) {
560                                 items_snippet.push_back(elem);
561                 }
562         }
563
564         script_select.clear_items ();
565         script_select.AddMenuElem (Menu_Helpers::MenuElem ("Scratch", *_menu_scratch));
566         script_select.AddMenuElem (Menu_Helpers::MenuElem ("Snippets", *_menu_snippet));
567         script_select.AddMenuElem (Menu_Helpers::MenuElem ("Actions", *_menu_actions));
568 }
569
570 void
571 LuaWindow::script_selection_changed (ScriptBufferPtr n, bool force)
572 {
573         if (n == _current_buffer && !force) {
574                 return;
575         }
576
577         Glib::RefPtr<Gtk::TextBuffer> tb (entry.get_buffer());
578
579         if ((n->flags & Buffer_Valid)) {
580                 _current_buffer->script = tb->get_text();
581         }
582
583         if (!(n->flags & Buffer_Valid)) {
584                 if (!n->load()) {
585                         append_text ("! Failed to load buffer.");
586                 }
587         }
588
589         if (n->flags & Buffer_Valid) {
590                 _current_buffer = n;
591                 _script_changed_connection.block ();
592                 tb->set_text (n->script);
593                 _script_changed_connection.unblock ();
594         } else {
595                 append_text ("! Failed to switch buffer.");
596         }
597         update_gui_state ();
598 }
599
600 void
601 LuaWindow::update_gui_state ()
602 {
603         const ScriptBuffer & sb (*_current_buffer);
604         std::string name;
605         if (sb.flags & Buffer_Scratch) {
606                 name = string_compose (_("Scratch Buffer %1"), sb.name);
607         } else if (sb.type == LuaScriptInfo::EditorAction) {
608                 name = string_compose (_("Action: '%1'"), sb.name);
609         } else if (sb.type == LuaScriptInfo::Snippet) {
610                 name = string_compose (_("Snippet: %1"), sb.name);
611         } else {
612                 cerr << "Invalid Script type\n";
613                 assert (0);
614                 return;
615         }
616         if (sb.flags & Buffer_Dirty) {
617                 name += " *";
618         }
619         script_select.set_text(name);
620
621         _btn_save.set_sensitive (sb.flags & Buffer_Dirty);
622         _btn_delete.set_sensitive (sb.flags & Buffer_Scratch); // TODO allow to remove user-scripts
623         _btn_revert.set_sensitive ((sb.flags & Buffer_Dirty) && (sb.flags & Buffer_HasFile));
624 }
625
626 void
627 LuaWindow::script_changed () {
628         if (_current_buffer->flags & Buffer_Dirty) {
629                 return;
630         }
631         _current_buffer->flags |= Buffer_Dirty;
632         update_gui_state ();
633 }
634
635 LuaWindow::ScriptBuffer::ScriptBuffer (const std::string& n)
636         : name (n)
637         , flags (Buffer_Scratch | Buffer_Valid)
638 {
639         script =
640                 "-- ardour { [\"type\"] = \"Snippet\", name = \"\" }\n"
641                 "-- function factory () return function () -- -- end end\n";
642 }
643
644 LuaWindow::ScriptBuffer::ScriptBuffer (LuaScriptInfoPtr p)
645         : name (p->name)
646         , path (p->path)
647         , flags (Buffer_HasFile)
648         , type (p->type)
649 {
650         if (!PBD::exists_and_writable (path)) {
651                 flags |= Buffer_ReadOnly;
652         }
653 }
654
655 #if 0
656 LuaWindow::ScriptBuffer::ScriptBuffer (const ScriptBuffer& other)
657         : script (other.script)
658         , name (other.name)
659         , path (other.path)
660         , flags (other.flags)
661         , type (other.type)
662 {
663 }
664 #endif
665
666 LuaWindow::ScriptBuffer::~ScriptBuffer ()
667 {
668 }
669
670 bool
671 LuaWindow::ScriptBuffer::load ()
672 {
673         if (!(flags & Buffer_HasFile)) return false;
674         if (flags & Buffer_Valid) return true;
675         try {
676                 script = Glib::file_get_contents (path);
677                 flags |= Buffer_Valid;
678         } catch (Glib::FileError e) {
679                 return false;
680         }
681         return true;
682 }