Dasher depends on glib, and newish glib comes with gio, so use gio's gvfs
[dasher.git] / Src / Gtk2 / dasher_editor_internal.cpp
blob1da13d293fa67a106fc8fec239932de0c72b0911
1 #include "config.h"
3 #include <cstring>
5 #include <glib/gi18n.h>
6 #ifdef HAVE_GIO
7 #include <gio/gio.h>
8 #endif
9 #include <gtk/gtk.h>
11 #ifdef WITH_MAEMO
12 #include "dasher_action_keyboard_maemo.h"
13 #else
14 #include "dasher_action_keyboard.h"
15 #endif
17 #ifndef WITH_MAEMO
18 #include "dasher_action_script.h"
19 #endif
21 #ifdef GNOME_SPEECH
22 #include "dasher_action_speech.h"
23 #endif
25 #include "dasher_editor_internal.h"
26 #include "dasher_external_buffer.h"
27 #include "dasher_internal_buffer.h"
28 #include "dasher_lock_dialogue.h"
29 #include "dasher_main.h"
30 //#include "game_mode_helper.h"
32 // TODO: Maybe reimplement something along the lines of the following, which used to be in edit.cc
34 // void set_mark() {
35 // GtkTextIter oBufferEnd;
36 // GtkTextIter oBufferStart;
37 // gtk_text_buffer_get_bounds( the_text_buffer, &oBufferStart, &oBufferEnd);
38 // gtk_text_buffer_create_mark(the_text_buffer, "new_start", &oBufferEnd, true);
39 // }
41 // const gchar *get_new_text() {
42 // GtkTextIter oNewStart;
43 // GtkTextIter oNewEnd;
44 // GtkTextIter oDummy;
46 // gtk_text_buffer_get_bounds( the_text_buffer, &oDummy, &oNewEnd);
47 // gtk_text_buffer_get_iter_at_mark( the_text_buffer, &oNewStart, gtk_text_buffer_get_mark(the_text_buffer, "new_start"));
49 // return gtk_text_buffer_get_text( the_text_buffer, &oNewStart, &oNewEnd, false );
51 // }
53 // ---
55 #define ACTION_STATE_SHOW 1
56 #define ACTION_STATE_CONTROL 2
57 #define ACTION_STATE_AUTO 4
59 typedef struct _EditorAction EditorAction;
61 struct _EditorAction {
62 DasherAction *pAction;
63 EditorAction *pNext;
64 EditorAction *pPrevious;
65 gint iControlID;
66 gint iID; // TODO: does this need to be separate from iControlID?
67 gboolean bShow;
68 gboolean bControl;
69 gboolean bAuto;
70 gint iNSub;
73 typedef struct _DasherEditorInternalPrivate DasherEditorInternalPrivate;
75 struct _DasherEditorInternalPrivate {
76 DasherMain *pDasherMain;
77 GtkTextView *pTextView;
78 GtkTextBuffer *pBuffer;
79 GtkVBox *pActionPane;
80 GtkClipboard *pTextClipboard;
81 GtkClipboard *pPrimarySelection;
82 GtkTable *pGameGroup;
83 GtkLabel *pGameInfoLabel;
84 EditorAction *pActionRing;
85 EditorAction *pActionIter;
86 gboolean bActionIterStarted;
87 gint iNextActionID;
88 IDasherBufferSet *pBufferSet;
89 IDasherBufferSet *pExternalBuffer;
90 // GameModeHelper *pGameModeHelper;
91 GtkTextMark *pNewMark;
92 DasherAppSettings *pAppSettings;
93 gchar *szFilename;
94 gboolean bFileModified; // TODO: Make this work properly, export to main for quit etc
97 #define DASHER_EDITOR_INTERNAL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_DASHER_EDITOR_INTERNAL, DasherEditorInternalPrivate))
99 /* Signals */
100 enum {
101 FILENAME_CHANGED,
102 BUFFER_CHANGED,
103 CONTEXT_CHANGED,
104 SIGNAL_NUM
107 //static guint dasher_editor_internal_signals[SIGNAL_NUM];
109 static DasherEditorInternal *g_pEditor;
111 G_DEFINE_TYPE(DasherEditorInternal, dasher_editor_internal, TYPE_DASHER_EDITOR);
113 static void dasher_editor_internal_finalize(GObject *pObject);
116 static void dasher_editor_internal_handle_font(DasherEditor *pSelf, const gchar *szFont);
118 gboolean dasher_editor_internal_command(DasherEditor *pSelf, const gchar *szCommand);
119 void dasher_editor_internal_initialise(DasherEditor *pSelf, DasherAppSettings *pAppSettings, DasherMain *pDasherMain, GladeXML *pGladeXML, const gchar *szFullPath);
121 /* Private methods */
122 static void dasher_editor_internal_select_all(DasherEditor *pSelf);
123 static void dasher_editor_internal_setup_actions(DasherEditor *pSelf);
124 static void dasher_editor_internal_add_action(DasherEditor *pSelf, DasherAction *pNewAction);
125 static EditorAction *dasher_editor_internal_get_action_by_id(DasherEditor *pSelf, int iID);
126 static void dasher_editor_internal_rebuild_action_pane(DasherEditor *pSelf);
127 //static void dasher_editor_internal_display_message(DasherEditor *pSelf, DasherMessageInfo *pMessageInfo);
128 static void dasher_editor_internal_check_activity(DasherEditor *pSelf, EditorAction *pAction);
129 static void dasher_editor_internal_action_save_state(DasherEditor *pSelf, EditorAction *pAction);
131 static void dasher_editor_internal_command_new(DasherEditor *pSelf);
132 static void dasher_editor_internal_command_open(DasherEditor *pSelf);
133 static void dasher_editor_internal_command_save(DasherEditor *pSelf, gboolean bPrompt, gboolean bAppend);
135 #ifdef HAVE_GIO
136 static void dasher_editor_internal_gvfs_print_error(DasherEditor *pSelf, GError *error, const char *myfilename);
137 static GFileOutputStream *append_or_replace_file(GFile *file, bool append, GError **error);
138 static gboolean dasher_editor_internal_gvfs_open_file(DasherEditor *pSelf, const char *filename, gchar ** buffer, gsize *size);
139 static gboolean dasher_editor_internal_gvfs_save_file(DasherEditor *pSelf, const char *filename, gchar * buffer, gsize length, bool append);
140 #else
141 static gboolean dasher_editor_internal_unix_vfs_open_file(DasherEditor *pSelf, const char *filename, gchar ** buffer, gsize *size);
142 static gboolean dasher_editor_internal_unix_vfs_save_file(DasherEditor *pSelf, const char *filename, gchar * buffer, gsize length, bool append);
143 #endif
145 static void dasher_editor_internal_set_filename(DasherEditor *pSelf, const gchar *szFilename);
147 // TODO: Should these be public?
148 static void dasher_editor_internal_convert(DasherEditor *pSelf);
149 static void dasher_editor_internal_protect(DasherEditor *pSelf);
151 static void dasher_editor_internal_new_buffer(DasherEditor *pSelf, const gchar *szFilename);
153 static void dasher_editor_internal_generate_filename(DasherEditor *pSelf);
154 static void dasher_editor_internal_open(DasherEditor *pSelf, const gchar *szFilename);
155 static bool dasher_editor_internal_save_as(DasherEditor *pSelf, const gchar *szFilename, bool bAppend);
156 static void dasher_editor_internal_create_buffer(DasherEditor *pSelf);
157 static void dasher_editor_internal_clear(DasherEditor *pSelf, gboolean bStore);
158 static void dasher_editor_internal_clipboard(DasherEditor *pSelf, clipboard_action act);
160 /* To be obsoleted by movement to GTK buffers */
161 void dasher_editor_internal_output(DasherEditor *pSelf, const gchar *szText, int iOffset);
162 void dasher_editor_internal_delete(DasherEditor *pSelf, int iLength, int iOffset);
163 const gchar *dasher_editor_internal_get_context(DasherEditor *pSelf, int iOffset, int iLength);
164 gint dasher_editor_internal_get_offset(DasherEditor *pSelf);
166 /* Events proagated from main */
167 void dasher_editor_internal_handle_stop(DasherEditor *pSelf);
168 void dasher_editor_internal_handle_start(DasherEditor *pSelf);
169 void dasher_editor_internal_handle_control(DasherEditor *pSelf, int iNodeID);
171 /* Action related methods - TODO: a lot of this should be moved to dasher_main (eg action on stop etc) - that way we get a better level of abstraction, and can incorporate commands from otehr modules too. Actions should only be externally visible as a list of string commands*/
172 void dasher_editor_internal_action_button(DasherEditor *pSelf, DasherAction *pAction);
173 void dasher_editor_internal_actions_start(DasherEditor *pSelf);
174 bool dasher_editor_internal_actions_more(DasherEditor *pSelf);
175 void dasher_editor_internal_actions_get_next(DasherEditor *pSelf, const gchar **szName, gint *iID, gboolean *bShow, gboolean *bControl, gboolean *bAuto);
176 void dasher_editor_internal_action_set_show(DasherEditor *pSelf, int iActionID, bool bValue);
177 void dasher_editor_internal_action_set_control(DasherEditor *pSelf, int iActionID, bool bValue);
178 void dasher_editor_internal_action_set_auto(DasherEditor *pSelf, int iActionID, bool bValue);
180 void dasher_editor_internal_grab_focus(DasherEditor *pSelf);
182 /* TODO: Tutorial editor should be a separate class */
183 //void dasher_editor_internal_start_tutorial(DasherEditor *pSelf);
185 /* Todo: possibly tidy up the need to have this public (quit in dasher_main possibly too connected) */
186 gboolean dasher_editor_internal_file_changed(DasherEditor *pSelf);
187 const gchar *dasher_editor_internal_get_filename(DasherEditor *pSelf);
189 const gchar *dasher_editor_internal_get_all_text(DasherEditor *pSelf);
190 const gchar *dasher_editor_internal_get_new_text(DasherEditor *pSelf);
192 static void dasher_editor_internal_handle_parameter_change(DasherEditor *pSelf, gint iParameter);
195 // Private methods not in class
196 extern "C" void delete_children_callback(GtkWidget *pWidget, gpointer pUserData);
197 extern "C" void main_window_realized(DasherMain *pMain, gpointer pUserData);
198 extern "C" void action_button_callback(GtkWidget *pWidget, gpointer pUserData);
199 extern "C" void context_changed_handler(GObject *pSource, gpointer pUserData);
200 extern "C" void buffer_changed_handler(GObject *pSource, gpointer pUserData);
201 extern "C" void handle_stop_event(GtkDasherControl *pDasherControl, gpointer data);
202 extern "C" void on_message(GtkDasherControl *pDasherControl, gpointer pMessageInfo, gpointer pUserData);
203 extern "C" void on_command(GtkDasherControl *pDasherControl, gchar *szCommand, gpointer pUserData);
204 extern "C" void handle_request_settings(GtkDasherControl * pDasherControl, gpointer data);
205 extern "C" void gtk2_edit_delete_callback(GtkDasherControl *pDasherControl, const gchar *szText, int iOffset, gpointer user_data);
206 extern "C" void gtk2_edit_output_callback(GtkDasherControl *pDasherControl, const gchar *szText, int iOffset, gpointer user_data);
207 extern "C" void convert_cb(GtkDasherControl *pDasherControl, gpointer pUserData);
208 extern "C" void protect_cb(GtkDasherControl *pDasherControl, gpointer pUserData);
210 static void
211 dasher_editor_internal_class_init(DasherEditorInternalClass *pClass) {
212 g_type_class_add_private(pClass, sizeof(DasherEditorInternalPrivate));
214 GObjectClass *pObjectClass = (GObjectClass *) pClass;
215 pObjectClass->finalize = dasher_editor_internal_finalize;
217 DasherEditorClass *pParentClass = (DasherEditorClass *)pClass;
219 pParentClass->initialise = dasher_editor_internal_initialise;
220 pParentClass->command = dasher_editor_internal_command;
221 pParentClass->output = dasher_editor_internal_output;
222 pParentClass->delete_text = dasher_editor_internal_delete;
223 pParentClass->get_context = dasher_editor_internal_get_context;
224 pParentClass->get_offset = dasher_editor_internal_get_offset;
225 pParentClass->handle_stop = dasher_editor_internal_handle_stop;
226 pParentClass->handle_start = dasher_editor_internal_handle_start;
227 pParentClass->handle_control = dasher_editor_internal_handle_control;
228 pParentClass->action_button = dasher_editor_internal_action_button;
229 pParentClass->actions_start = dasher_editor_internal_actions_start;
230 pParentClass->actions_more = dasher_editor_internal_actions_more;
231 pParentClass->actions_get_next = dasher_editor_internal_actions_get_next;
232 pParentClass->action_set_show = dasher_editor_internal_action_set_show;
233 pParentClass->action_set_control = dasher_editor_internal_action_set_control;
234 pParentClass->action_set_auto = dasher_editor_internal_action_set_auto;
235 pParentClass->grab_focus = dasher_editor_internal_grab_focus;
236 pParentClass->file_changed = dasher_editor_internal_file_changed;
237 pParentClass->get_filename = dasher_editor_internal_get_filename;
238 pParentClass->get_all_text = dasher_editor_internal_get_all_text;
239 pParentClass->get_new_text = dasher_editor_internal_get_new_text;
240 pParentClass->handle_parameter_change = dasher_editor_internal_handle_parameter_change;
243 static void
244 dasher_editor_internal_init(DasherEditorInternal *pDasherControl) {
245 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pDasherControl);
247 pPrivate->pBufferSet = NULL;
248 pPrivate->pExternalBuffer = NULL;
249 pPrivate->szFilename = NULL;
250 pPrivate->pTextClipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
251 pPrivate->pPrimarySelection = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
252 pPrivate->pActionRing = NULL;
253 pPrivate->iNextActionID = 0;
254 // pPrivate->pGameModeHelper = NULL;
255 pPrivate->bFileModified = FALSE;
258 static void
259 dasher_editor_internal_finalize(GObject *pObject) {
260 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pObject);
262 EditorAction *pCurrentAction = pPrivate->pActionRing;
264 if(pCurrentAction) {
265 bool bStarted = false;
267 while(!bStarted || (pCurrentAction != pPrivate->pActionRing)) {
268 bStarted = true;
269 dasher_action_deactivate(pCurrentAction->pAction);
270 g_object_unref(G_OBJECT(pCurrentAction->pAction));
271 pCurrentAction = pCurrentAction->pNext;
275 if(pPrivate->pBufferSet)
276 g_object_unref(G_OBJECT(pPrivate->pBufferSet));
278 if(pPrivate->szFilename)
279 g_free(pPrivate->szFilename);
282 /* Public methods */
283 DasherEditorInternal *
284 dasher_editor_internal_new() {
285 DasherEditorInternal *pDasherEditor;
286 pDasherEditor = (DasherEditorInternal *)(g_object_new(dasher_editor_internal_get_type(), NULL));
288 g_pEditor = pDasherEditor;
290 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pDasherEditor);
292 GtkWidget *pScrolledWindow = gtk_scrolled_window_new(NULL, NULL);
294 GtkWidget *pTextView = gtk_text_view_new();
295 gtk_widget_grab_focus(pTextView);
298 pPrivate->pTextView = GTK_TEXT_VIEW(pTextView);
300 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(pTextView),
301 GTK_WRAP_WORD);
303 gtk_container_add(GTK_CONTAINER(pScrolledWindow), pTextView);
305 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pScrolledWindow),
306 GTK_POLICY_AUTOMATIC,
307 GTK_POLICY_AUTOMATIC);
309 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pScrolledWindow),
310 GTK_SHADOW_IN);
312 gtk_box_pack_start(GTK_BOX(&(pDasherEditor->parent.box)), pScrolledWindow, true, true, 0);
315 gtk_widget_show_all(GTK_WIDGET(&(pDasherEditor->parent.box)));
317 return pDasherEditor;
320 void
321 dasher_editor_internal_initialise(DasherEditor *pSelf, DasherAppSettings *pAppSettings, DasherMain *pDasherMain, GladeXML *pGladeXML, const gchar *szFullPath) {
323 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
325 pPrivate->pAppSettings = pAppSettings;
326 pPrivate->pDasherMain = pDasherMain;
328 dasher_editor_internal_handle_font(pSelf,
329 dasher_app_settings_get_string(pPrivate->pAppSettings,
330 APP_SP_EDIT_FONT));
332 GtkVBox *pActionPane = GTK_VBOX(glade_xml_get_widget(pGladeXML, "vbox39"));
333 pPrivate->pBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pPrivate->pTextView));
335 gtk_widget_show_all(GTK_WIDGET(pPrivate->pTextView));
337 GtkTextIter oStartIter;
338 gtk_text_buffer_get_start_iter(pPrivate->pBuffer, &oStartIter);
339 pPrivate->pNewMark = gtk_text_buffer_create_mark(pPrivate->pBuffer, NULL, &oStartIter, TRUE);
341 pPrivate->pActionPane = pActionPane;
343 // TODO: is this still needed?
344 dasher_editor_internal_create_buffer(pSelf);
346 dasher_editor_internal_setup_actions(pSelf);
348 // TODO: see note in command_new method
349 if(szFullPath)
350 dasher_editor_internal_open(pSelf, szFullPath);
351 else {
352 dasher_editor_internal_generate_filename(pSelf);
353 dasher_editor_internal_clear(pSelf, false);
356 // pPrivate->pGameModeHelper = GAME_MODE_HELPER(game_mode_helper_new(pGladeXML, (void*)pSelf));
359 static void
360 dasher_editor_internal_clipboard(DasherEditor *pSelf, clipboard_action act) {
361 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
363 GtkTextIter *start = new GtkTextIter;
364 GtkTextIter *end = new GtkTextIter;
366 gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(pPrivate->pBuffer), start, 0);
367 gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(pPrivate->pBuffer), end, -1);
369 gchar *the_text = gtk_text_buffer_get_text(pPrivate->pBuffer, start, end, TRUE);
371 switch (act) {
372 case CLIPBOARD_CUT:
373 gtk_text_buffer_cut_clipboard(pPrivate->pBuffer, pPrivate->pTextClipboard, TRUE);
374 break;
375 case CLIPBOARD_COPY:
376 gtk_text_buffer_copy_clipboard(pPrivate->pBuffer, pPrivate->pTextClipboard);
377 break;
378 case CLIPBOARD_PASTE:
379 gtk_text_buffer_paste_clipboard(pPrivate->pBuffer, pPrivate->pTextClipboard, NULL, TRUE);
380 break;
381 case CLIPBOARD_COPYALL:
382 gtk_clipboard_set_text(pPrivate->pTextClipboard, the_text, strlen(the_text));
383 gtk_clipboard_set_text(pPrivate->pPrimarySelection, the_text, strlen(the_text));
385 break;
386 case CLIPBOARD_SELECTALL:
387 dasher_editor_internal_select_all(pSelf);
388 break;
389 case CLIPBOARD_CLEAR:
390 gtk_text_buffer_set_text(pPrivate->pBuffer, "", 0);
391 break;
393 g_free(the_text);
395 delete start;
396 delete end;
399 void dasher_editor_internal_cleartext(DasherEditorInternal *pSelf)
401 dasher_editor_internal_clear((DasherEditor *)pSelf, true);
405 void
406 dasher_editor_internal_handle_stop(DasherEditor *pSelf) {
407 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
409 // See if anything is set to auto:
410 EditorAction *pCurrentAction = pPrivate->pActionRing;
412 if(pCurrentAction) {
413 bool bStarted = false;
415 while(!bStarted || (pCurrentAction != pPrivate->pActionRing)) {
416 bStarted = true;
417 if(pCurrentAction->bAuto)
418 dasher_action_execute(pCurrentAction->pAction, DASHER_EDITOR(pSelf), -1);
419 pCurrentAction = pCurrentAction->pNext;
424 void
425 dasher_editor_internal_handle_start(DasherEditor *pSelf) {
426 // The edit box keeps track of where we started
428 // TODO: This should be filtered through the buffer, rather than directly to the edit box
429 // set_mark();
432 /* TODO: This is obsolete - sort this out when commands are reconsidered */
433 void
434 dasher_editor_internal_handle_control(DasherEditor *pSelf, int iNodeID) {
435 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
437 if(iNodeID == Dasher::CControlManager::CTL_USER + 1)
438 dasher_editor_internal_clear(pSelf, false); // Clear node is a special case (it shouldn't be)
439 else {
440 EditorAction *pCurrentAction = pPrivate->pActionRing;
441 bool bStarted = false;
443 while(!bStarted || (pCurrentAction != pPrivate->pActionRing)) {
444 bStarted = true;
445 if((iNodeID >= pCurrentAction->iControlID) && (iNodeID <= pCurrentAction->iControlID + pCurrentAction->iNSub)) {
446 dasher_action_execute(pCurrentAction->pAction, DASHER_EDITOR(pSelf), iNodeID - pCurrentAction->iControlID - 1);
447 // dasher_editor_internal_clear(pSelf, true);
449 pCurrentAction = pCurrentAction->pNext;
454 // TODO: Think about changing signals so we don't need to do this translation
456 struct SControlMap {
457 int iEvent;
458 int iDir;
459 int iDist;
460 bool bDelete;
463 static struct SControlMap sMap[] = {
464 {Dasher::CControlManager::CTL_MOVE_FORWARD_CHAR, EDIT_FORWARDS, EDIT_CHAR, false},
465 {Dasher::CControlManager::CTL_MOVE_FORWARD_WORD, EDIT_FORWARDS, EDIT_WORD, false},
466 {Dasher::CControlManager::CTL_MOVE_FORWARD_LINE, EDIT_FORWARDS, EDIT_LINE, false},
467 {Dasher::CControlManager::CTL_MOVE_FORWARD_FILE, EDIT_FORWARDS, EDIT_FILE, false},
468 {Dasher::CControlManager::CTL_MOVE_BACKWARD_CHAR, EDIT_BACKWARDS, EDIT_CHAR, false},
469 {Dasher::CControlManager::CTL_MOVE_BACKWARD_WORD, EDIT_BACKWARDS, EDIT_WORD, false},
470 {Dasher::CControlManager::CTL_MOVE_BACKWARD_LINE, EDIT_BACKWARDS, EDIT_LINE, false},
471 {Dasher::CControlManager::CTL_MOVE_BACKWARD_FILE, EDIT_BACKWARDS, EDIT_FILE, false},
472 {Dasher::CControlManager::CTL_DELETE_FORWARD_CHAR, EDIT_FORWARDS, EDIT_CHAR, true},
473 {Dasher::CControlManager::CTL_DELETE_FORWARD_WORD, EDIT_FORWARDS, EDIT_WORD, true},
474 {Dasher::CControlManager::CTL_DELETE_FORWARD_LINE, EDIT_FORWARDS, EDIT_LINE, true},
475 {Dasher::CControlManager::CTL_DELETE_FORWARD_FILE, EDIT_FORWARDS, EDIT_FILE, true},
476 {Dasher::CControlManager::CTL_DELETE_BACKWARD_CHAR, EDIT_BACKWARDS, EDIT_CHAR, true},
477 {Dasher::CControlManager::CTL_DELETE_BACKWARD_WORD, EDIT_BACKWARDS, EDIT_WORD, true},
478 {Dasher::CControlManager::CTL_DELETE_BACKWARD_LINE, EDIT_BACKWARDS, EDIT_LINE, true},
479 {Dasher::CControlManager::CTL_DELETE_BACKWARD_FILE, EDIT_BACKWARDS, EDIT_FILE, true}
482 if(pPrivate->pBufferSet) {
483 for(unsigned int i(0); i < sizeof(sMap)/sizeof(struct SControlMap); ++i) {
484 if(sMap[i].iEvent == iNodeID) {
485 if(sMap[i].bDelete)
486 idasher_buffer_set_edit_delete(pPrivate->pBufferSet, sMap[i].iDir, sMap[i].iDist);
487 else
488 idasher_buffer_set_edit_move(pPrivate->pBufferSet, sMap[i].iDir, sMap[i].iDist);
495 void
496 dasher_editor_internal_action_button(DasherEditor *pSelf, DasherAction *pAction) {
497 if(pAction) {
498 dasher_action_execute(pAction, DASHER_EDITOR(pSelf), -1);
499 dasher_editor_internal_clear(pSelf, true);
501 else { // Clear button
502 dasher_editor_internal_clear(pSelf, false);
506 static void
507 dasher_editor_internal_clear(DasherEditor *pSelf, gboolean bStore) {
508 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
510 if(IS_DASHER_INTERNAL_BUFFER(pPrivate->pBufferSet))
511 dasher_internal_buffer_clear(DASHER_INTERNAL_BUFFER(pPrivate->pBufferSet));
515 void
516 dasher_editor_internal_actions_start(DasherEditor *pSelf) {
517 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
519 pPrivate->bActionIterStarted = false;
520 pPrivate->pActionIter = pPrivate->pActionRing;
523 bool
524 dasher_editor_internal_actions_more(DasherEditor *pSelf) {
525 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
527 return(!pPrivate->bActionIterStarted || (pPrivate->pActionIter != pPrivate->pActionRing));
530 void
531 dasher_editor_internal_actions_get_next(DasherEditor *pSelf, const gchar **szName, gint *iID, gboolean *bShow, gboolean *bControl, gboolean *bAuto) {
532 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
534 *szName = dasher_action_get_name(pPrivate->pActionIter->pAction);
535 *iID = pPrivate->pActionIter->iID;
536 *bShow = pPrivate->pActionIter->bShow;
537 *bControl = pPrivate->pActionIter->bControl;
538 *bAuto = pPrivate->pActionIter->bAuto;
540 pPrivate->pActionIter = pPrivate->pActionIter->pNext;
541 pPrivate->bActionIterStarted = true;
544 void
545 dasher_editor_internal_action_set_show(DasherEditor *pSelf, int iActionID, bool bValue) {
546 EditorAction *pAction;
547 pAction = dasher_editor_internal_get_action_by_id(pSelf, iActionID);
549 if(pAction) {
550 pAction->bShow = bValue;
551 dasher_editor_internal_check_activity(pSelf, pAction);
552 dasher_editor_internal_rebuild_action_pane(pSelf);
554 dasher_editor_internal_action_save_state(pSelf, pAction);
558 void
559 dasher_editor_internal_action_set_control(DasherEditor *pSelf, int iActionID, bool bValue) {
560 // TODO: Need to actually change behaviour in resonse to these calls
562 // TODO: Reimplement
564 // EditorAction *pAction;
565 // pAction = dasher_editor_internal_get_action_by_id(pSelf, iActionID);
567 // if(pAction) {
568 // pAction->bControl = bValue;
569 // dasher_editor_internal_check_activity(pSelf, pAction);
570 // if(bValue)
571 // gtk_dasher_control_connect_node(GTK_DASHER_CONTROL(pDasherWidget), pAction->iControlID, Dasher::CControlManager::CTL_USER, -2);
572 // else
573 // gtk_dasher_control_disconnect_node(GTK_DASHER_CONTROL(pDasherWidget), pAction->iControlID, Dasher::CControlManager::CTL_USER);
575 // dasher_editor_internal_action_save_state(pSelf, pAction);
576 // }
579 void
580 dasher_editor_internal_action_set_auto(DasherEditor *pSelf, int iActionID, bool bValue) {
581 EditorAction *pAction;
582 pAction = dasher_editor_internal_get_action_by_id(pSelf, iActionID);
584 if(pAction) {
585 pAction->bAuto = bValue;
586 dasher_editor_internal_check_activity(pSelf, pAction);
588 dasher_editor_internal_action_save_state(pSelf, pAction);
592 void
593 dasher_editor_internal_grab_focus(DasherEditor *pSelf) {
594 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
596 if(pPrivate->pTextView)
597 gtk_widget_grab_focus(GTK_WIDGET(pPrivate->pTextView));
601 static void
602 dasher_editor_internal_create_buffer(DasherEditor *pSelf) {
603 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
605 /* Make an external buffer anyway, for keyboard command */
606 /* TODO: Review this */
607 if(!(pPrivate->pExternalBuffer))
608 pPrivate->pExternalBuffer = IDASHER_BUFFER_SET(dasher_external_buffer_new());
610 if(!(pPrivate->pBufferSet))
611 pPrivate->pBufferSet = IDASHER_BUFFER_SET(dasher_internal_buffer_new(pPrivate->pTextView));
613 // TODO: Fix this
614 g_signal_connect(G_OBJECT(pPrivate->pBufferSet), "offset_changed", G_CALLBACK(context_changed_handler), pSelf);
615 g_signal_connect(G_OBJECT(pPrivate->pBufferSet), "buffer_changed", G_CALLBACK(buffer_changed_handler), pSelf);
618 void
619 dasher_editor_internal_output(DasherEditor *pSelf, const gchar *szText, int iOffset) {
620 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
622 // TODO: tidy this up, actionlookup by name, more flexible
623 // definition of space
624 // Python scripting?
625 if(!strcmp(szText, " ")) {
626 gboolean bActionIterStarted = false;
627 EditorAction *pActionIter = pPrivate->pActionRing;
629 while((pActionIter != pPrivate->pActionRing) || !bActionIterStarted) {
630 bActionIterStarted = true;
632 if(!strcmp(dasher_action_get_name(pActionIter->pAction), "Speak")) {
633 dasher_action_preview(pActionIter->pAction, DASHER_EDITOR(pSelf));
636 pActionIter = pActionIter->pNext;
640 if(pPrivate->pBufferSet)
641 idasher_buffer_set_insert(pPrivate->pBufferSet, szText, iOffset);
643 // if(pPrivate->pGameModeHelper)
644 // game_mode_helper_output(pPrivate->pGameModeHelper, szText);
646 pPrivate->bFileModified = TRUE;
649 void
650 dasher_editor_internal_delete(DasherEditor *pSelf, int iLength, int iOffset) {
651 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
653 if(pPrivate->pBufferSet)
654 idasher_buffer_set_delete(pPrivate->pBufferSet, iLength, iOffset);
656 // if(pPrivate->pGameModeHelper)
657 // game_mode_helper_delete(pPrivate->pGameModeHelper, iLength);
659 pPrivate->bFileModified = TRUE;
662 const gchar *
663 dasher_editor_internal_get_context(DasherEditor *pSelf, int iOffset, int iLength) {
664 // TODO: Check where this function is used
665 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
667 const gchar *szContext;
669 if(pPrivate->pBufferSet)
670 szContext = idasher_buffer_set_get_context(pPrivate->pBufferSet, iOffset, iLength);
671 else
672 szContext = "";
674 // TODO: reimplement
675 // if(szContext && (strlen(szContext) > 0))
676 // gtk_dasher_control_set_context( GTK_DASHER_CONTROL(pDasherWidget), szContext );
677 return szContext;
680 gint
681 dasher_editor_internal_get_offset(DasherEditor *pSelf) {
682 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
683 return idasher_buffer_set_get_offset(pPrivate->pBufferSet);
686 static void
687 dasher_editor_internal_generate_filename(DasherEditor *pSelf) {
688 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
690 gchar *szNewFilename = NULL;
692 if( dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_TIME_STAMP )) {
693 // Build a filename based on the current time and date
694 tm *t_struct;
695 time_t ctime;
696 char cwd[1000];
697 char tbuffer[200];
699 ctime = time(NULL);
701 t_struct = localtime(&ctime);
703 getcwd(cwd, 1000);
704 snprintf(tbuffer, 200, "dasher-%04d%02d%02d-%02d%02d.txt", (t_struct->tm_year + 1900), (t_struct->tm_mon + 1), t_struct->tm_mday, t_struct->tm_hour, t_struct->tm_min);
706 szNewFilename = g_build_path("/", cwd, tbuffer, NULL);
709 dasher_editor_internal_set_filename(pSelf, szNewFilename);
711 g_free(szNewFilename);
714 static void
715 dasher_editor_internal_open(DasherEditor *pSelf, const gchar *szFilename) {
716 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
718 gsize size;
719 gchar *buffer;
721 #ifdef HAVE_GIO
722 if(!dasher_editor_internal_gvfs_open_file(pSelf, szFilename, &buffer, &size)) {
723 return;
725 #else
726 if(!dasher_editor_internal_unix_vfs_open_file(pSelf, szFilename, &buffer, &size)) {
727 return;
729 #endif
731 // FIXME - REIMPLEMENT (shouldn't happen through core)
732 // dasher_clear();
734 if(size != 0) {
735 // Don't attempt to insert new text if the file is empty as it makes
736 // GTK cry
737 if(!g_utf8_validate(buffer, size, NULL)) { // PRLW: size as gssize = signed int
738 // It's not UTF8, so we do the best we can...
740 // If there are zero bytes in the file then we have a problem -
741 // for now, just assert that we can't load these files.
742 for(gsize i = 0; i < size; ++i)
743 if(buffer[i] == 0) {
744 // GtkWidget *pErrorBox = gtk_message_dialog_new(GTK_WINDOW(window),
745 // GTK_DIALOG_MODAL,
746 // GTK_MESSAGE_ERROR,
747 // GTK_BUTTONS_OK,
748 // "Could not open the file \"%s\". Please note that Dasher cannot load files containing binary data, which may be the cause of this error.\n",
749 // myfilename);
750 GtkWidget *pErrorBox = gtk_message_dialog_new(NULL,
751 GTK_DIALOG_MODAL,
752 GTK_MESSAGE_ERROR,
753 GTK_BUTTONS_OK,
754 "Could not open the file \"%s\". Please note that Dasher cannot load files containing binary data, which may be the cause of this error.\n",
755 szFilename);
756 gtk_dialog_run(GTK_DIALOG(pErrorBox));
757 gtk_widget_destroy(pErrorBox);
758 return;
761 pPrivate->bFileModified = TRUE;
763 gsize iNewSize;
764 gchar *buffer2 = g_strdup(g_locale_to_utf8(buffer, size, NULL, &iNewSize, NULL));
766 // TODO: This function probably needs more thought
768 // const gchar *pEnd;
769 //gboolean bValid = g_utf8_validate(buffer2, -1, &pEnd);
771 g_free(buffer);
772 buffer = buffer2;
773 size = iNewSize;
775 gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(pPrivate->pBuffer), buffer, size);
776 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(pPrivate->pTextView), gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(pPrivate->pBuffer)));
779 dasher_editor_internal_set_filename(pSelf, szFilename);
782 static bool
783 dasher_editor_internal_save_as(DasherEditor *pSelf, const gchar *szFilename, bool bAppend) {
784 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
786 unsigned long long length;
787 gchar *inbuffer, *outbuffer = NULL;
788 // gsize bytes_read, bytes_written;
789 gsize bytes_written;
790 // GError *error = NULL;
791 GtkTextIter *start, *end;
792 // GIConv cd;
794 start = new GtkTextIter;
795 end = new GtkTextIter;
797 gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(pPrivate->pBuffer), start, 0);
798 gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(pPrivate->pBuffer), end, -1);
800 inbuffer = gtk_text_iter_get_slice(start, end);
802 // g_message("String %s", inbuffer);
804 //length = gtk_text_iter_get_offset(end) - gtk_text_iter_get_offset(start);
805 //length = gtk_text_buffer_get_byte_count(GTK_TEXT_BUFFER(the_text_buffer));
807 // I'm pretty certain that this is null terminated, but not 100%
808 length = strlen(inbuffer);
810 // g_message("Length is %d", length);
812 outbuffer = (char *)malloc((length + 1) * sizeof(gchar));
813 memcpy((void *)outbuffer, (void *)inbuffer, length * sizeof(gchar));
814 outbuffer[length] = 0;
815 g_free(inbuffer);
816 inbuffer = outbuffer;
817 outbuffer = NULL;
819 // switch (fileencoding) {
820 // case Dasher::Opts::UserDefault:
821 // case Dasher::Opts::AlphabetDefault:
822 // //FIXME - need to call GetAlphabetType and do appropriate stuff regarding
823 // //the character set. Arguably we should always be saving in either UTF-8 or
824 // //the user's locale (which may, of course, be UTF-8) because otherwise
825 // //we're going to read in rubbish, and we shouldn't be encouraging weird
826 // //codepage madness any further
828 // //FIXME - error handling
829 // outbuffer = g_locale_from_utf8(inbuffer, -1, &bytes_read, &bytes_written, &error);
830 // if(outbuffer == NULL) {
831 // // We can't represent the text in the current locale, so fall back to
832 // // UTF-8
833 // outbuffer = inbuffer;
834 // bytes_written = length;
835 // }
836 // case Dasher::Opts::UTF8:
837 // outbuffer = inbuffer;
838 // bytes_written = length;
839 // break;
840 // // Does /anyone/ want to save text files in UTF16?
841 // // (in any case, my opinions regarding encouragement of data formats with
842 // // endianness damage are almost certainly unprintable)
844 // case Dasher::Opts::UTF16LE:
845 // cd = g_iconv_open("UTF16LE", "UTF8");
846 // outbuffer = g_convert_with_iconv(inbuffer, -1, cd, &bytes_read, &bytes_written, &error);
847 // break;
848 // case Dasher::Opts::UTF16BE:
849 // cd = g_iconv_open("UTF16BE", "UTF8");
850 // outbuffer = g_convert_with_iconv(inbuffer, -1, cd, &bytes_read, &bytes_written, &error);
851 // break;
852 // default:
853 outbuffer = inbuffer;
854 bytes_written = length;
855 // }
857 #ifdef HAVE_GIO
858 if(!dasher_editor_internal_gvfs_save_file(pSelf, szFilename, outbuffer, bytes_written, bAppend)) {
859 return false;
861 #else
862 if(!dasher_editor_internal_unix_vfs_save_file(pSelf, szFilename, outbuffer, bytes_written, bAppend)) {
863 return false;
865 #endif
867 pPrivate->bFileModified = FALSE;
869 dasher_editor_internal_set_filename(pSelf, szFilename);
871 return true;
874 // void
875 // dasher_editor_internal_start_tutorial(DasherEditor *pSelf) {
876 // DasherEditorInternalPrivate *pPrivate = (DasherEditorInternalPrivate *)(pSelf->private_data);
878 // // TODO: reimplement
879 // // pPrivate->pGameModeHelper = GAME_MODE_HELPER(game_mode_helper_new(GTK_DASHER_CONTROL(pDasherWidget)));
880 // }
882 gboolean
883 dasher_editor_internal_command(DasherEditor *pSelf, const gchar *szCommand) {
884 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
886 if(!strcmp(szCommand, "new")) { //select_new_file
887 dasher_editor_internal_command_new(pSelf);
888 return TRUE;
891 if(!strcmp(szCommand, "open")) { //select open file
892 dasher_editor_internal_command_open(pSelf);
893 return TRUE;
896 if(!strcmp(szCommand, "save")) { //save_file
897 dasher_editor_internal_command_save(pSelf, FALSE, FALSE);
898 return TRUE;
901 if(!strcmp(szCommand, "saveas")) { // select_save_file_as
902 dasher_editor_internal_command_save(pSelf, TRUE, FALSE);
903 return TRUE;
906 if(!strcmp(szCommand, "append")) { // select_append_file
907 dasher_editor_internal_command_save(pSelf, TRUE, TRUE);
908 return TRUE;
911 if(!strcmp(szCommand, "cut")) { // clipboard_cut
912 dasher_editor_internal_clipboard(pSelf, CLIPBOARD_CUT);
913 return TRUE;
916 if(!strcmp(szCommand, "copy")) { // clipboard_copy
917 dasher_editor_internal_clipboard(pSelf, CLIPBOARD_COPY);
918 return TRUE;
921 if(!strcmp(szCommand, "copyall")) { // clipboard_copyall
922 dasher_editor_internal_clipboard(pSelf, CLIPBOARD_COPYALL);
923 return TRUE;
926 if(!strcmp(szCommand, "paste")) { // clipboard_paste
927 dasher_editor_internal_clipboard(pSelf, CLIPBOARD_PASTE);
928 return TRUE;
931 // TODO: This isn't actually accessible from anywhere
932 if(!strcmp(szCommand, "selectall")) { // clipboard_paste
933 dasher_editor_internal_clipboard(pSelf, CLIPBOARD_SELECTALL);
934 return TRUE;
937 /* TODO: We need a rethink here */
938 const gchar *szForwardCommand = NULL;
939 gint iSubCommand = 0;
941 if(!strcmp(szCommand, "speakall")) {
942 szForwardCommand = "Speak";
943 iSubCommand = 0;
945 else if(!strcmp(szCommand, "speaklast")) {
946 szForwardCommand = "Speak";
947 iSubCommand = 1;
949 else if(!strcmp(szCommand, "speakrepeat")) {
950 szForwardCommand = "Speak";
951 iSubCommand = 2;
954 if(szForwardCommand) {
955 gboolean bActionIterStarted = false;
956 EditorAction *pActionIter = pPrivate->pActionRing;
958 while((pActionIter != pPrivate->pActionRing) || !bActionIterStarted) {
959 bActionIterStarted = true;
961 if(!strcmp(dasher_action_get_name(pActionIter->pAction), szForwardCommand)) {
962 dasher_action_execute(pActionIter->pAction, DASHER_EDITOR(pSelf), iSubCommand);
963 return TRUE;
966 pActionIter = pActionIter->pNext;
968 return TRUE;
971 return FALSE;
975 void
976 dasher_editor_internal_handle_font(DasherEditor *pSelf, const gchar *szFont) {
977 if(strcmp(szFont, "")) {
978 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
980 PangoFontDescription *pFD = pango_font_description_from_string(szFont);
981 gtk_widget_modify_font(GTK_WIDGET(pPrivate->pTextView), pFD);
986 gboolean
987 dasher_editor_internal_file_changed(DasherEditor *pSelf) {
988 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
989 return pPrivate->bFileModified;
992 const gchar *
993 dasher_editor_internal_get_filename(DasherEditor *pSelf) {
994 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
996 return pPrivate->szFilename;
999 // TODO: We shouldn't need to know about the buffer here - make this a method of the buffer set
1000 const gchar *
1001 dasher_editor_internal_get_all_text(DasherEditor *pSelf) {
1002 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1004 GtkTextIter oStart;
1005 GtkTextIter oEnd;
1007 gtk_text_buffer_get_start_iter(pPrivate->pBuffer, &oStart);
1008 gtk_text_buffer_get_end_iter(pPrivate->pBuffer, &oEnd);
1010 pPrivate->pNewMark = gtk_text_buffer_create_mark(pPrivate->pBuffer, NULL, &oEnd, TRUE);
1012 return gtk_text_buffer_get_text(pPrivate->pBuffer, &oStart, &oEnd, false );
1015 const gchar *
1016 dasher_editor_internal_get_new_text(DasherEditor *pSelf) {
1017 // TODO: Implement this properly
1018 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1020 GtkTextIter oStart;
1021 GtkTextIter oEnd;
1023 gtk_text_buffer_get_end_iter(pPrivate->pBuffer, &oEnd);
1024 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, &oStart, pPrivate->pNewMark);
1026 const gchar *szRetVal = gtk_text_buffer_get_text(pPrivate->pBuffer, &oStart, &oEnd, false );
1028 pPrivate->pNewMark = gtk_text_buffer_create_mark(pPrivate->pBuffer, NULL, &oEnd, TRUE);
1030 return szRetVal;
1034 /* Private methods */
1035 static void
1036 dasher_editor_internal_select_all(DasherEditor *pSelf) {
1037 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1038 GtkTextIter *start, *end;
1040 start = new GtkTextIter;
1041 end = new GtkTextIter;
1043 gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(pPrivate->pBuffer), start, 0);
1044 gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(pPrivate->pBuffer), end, -1);
1046 GtkTextMark *selection = gtk_text_buffer_get_mark(pPrivate->pBuffer, "selection_bound");
1047 GtkTextMark *cursor = gtk_text_buffer_get_mark(pPrivate->pBuffer, "insert");
1049 gtk_text_buffer_move_mark(pPrivate->pBuffer, selection, start);
1050 gtk_text_buffer_move_mark(pPrivate->pBuffer, cursor, end);
1052 delete start;
1053 delete end;
1056 static void
1057 dasher_editor_internal_setup_actions(DasherEditor *pSelf) {
1058 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1060 // TODO: Activate and deactivate methods for actions
1061 // TODO: Clear shouldn't be a special case (include support for false in clear method)
1063 #ifdef GNOME_SPEECH
1064 dasher_editor_internal_add_action(pSelf, DASHER_ACTION(dasher_action_speech_new()));
1065 #endif
1067 dasher_editor_internal_add_action(pSelf, DASHER_ACTION(dasher_action_keyboard_new(pPrivate->pExternalBuffer)));
1069 #ifdef WITH_MAEMO
1070 dasher_editor_internal_add_action(pSelf, DASHER_ACTION(dasher_action_keyboard_maemo_new()));
1071 #else
1072 // dasher_editor_internal_add_action(pSelf, DASHER_ACTION(dasher_action_copy_new(pSelf)));
1074 GDir *pDirectory;
1075 G_CONST_RETURN gchar *szFilename;
1078 gchar *szUserScriptDir = new gchar[strlen(dasher_app_settings_get_string(pPrivate->pAppSettings, SP_USER_LOC))+9];
1079 strcpy(szUserScriptDir, dasher_app_settings_get_string(pPrivate->pAppSettings, SP_USER_LOC));
1080 strcat(szUserScriptDir, "scripts/");
1082 pDirectory = g_dir_open(szUserScriptDir, 0, NULL);
1084 if(pDirectory) {
1085 while((szFilename = g_dir_read_name(pDirectory))) {
1086 dasher_editor_internal_add_action(pSelf, DASHER_ACTION(dasher_action_script_new(szUserScriptDir, szFilename)));
1089 g_dir_close(pDirectory);
1092 delete[] szUserScriptDir;
1094 gchar *szSystemScriptDir = new gchar[strlen(dasher_app_settings_get_string(pPrivate->pAppSettings, SP_SYSTEM_LOC))+9];
1095 strcpy(szSystemScriptDir, dasher_app_settings_get_string(pPrivate->pAppSettings, SP_SYSTEM_LOC));
1096 strcat(szSystemScriptDir, "scripts/");
1098 pDirectory = g_dir_open(szSystemScriptDir, 0, NULL);
1100 if(pDirectory) {
1101 while((szFilename = g_dir_read_name(pDirectory))) {
1102 dasher_editor_internal_add_action(pSelf, DASHER_ACTION(dasher_action_script_new(szSystemScriptDir, szFilename)));
1105 g_dir_close(pDirectory);
1108 delete[] szSystemScriptDir;
1109 #endif
1111 // TODO: Reimplement
1113 // // TODO: This doesn't get re-called if the preferences change
1115 // gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pDasherWidget), Dasher::CControlManager::CTL_USER, "Actions", -1 );
1116 // gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pDasherWidget), Dasher::CControlManager::CTL_USER, Dasher::CControlManager::CTL_ROOT, -2);
1117 // int iControlOffset(1);
1119 // gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pDasherWidget), Dasher::CControlManager::CTL_USER + iControlOffset, "Clear", -1 );
1120 // gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pDasherWidget), Dasher::CControlManager::CTL_USER + iControlOffset, Dasher::CControlManager::CTL_USER, -2);
1121 // gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pDasherWidget), -1, Dasher::CControlManager::CTL_USER + iControlOffset, -2);
1122 // ++iControlOffset;
1124 // EditorAction *pCurrentAction = pPrivate->pActionRing;
1125 // bool bStarted = false;
1127 // while(!bStarted || (pCurrentAction != pPrivate->pActionRing)) {
1128 // bStarted = true;
1130 // if(pCurrentAction->bControl) {
1131 // gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pDasherWidget), Dasher::CControlManager::CTL_USER + iControlOffset, dasher_action_get_name(pCurrentAction->pAction), -1 );
1132 // gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pDasherWidget), Dasher::CControlManager::CTL_USER + iControlOffset, Dasher::CControlManager::CTL_USER, -2);
1134 // int iNSub(dasher_action_get_sub_count(pCurrentAction->pAction));
1136 // if(iNSub == 0) {
1137 // gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pDasherWidget), -1, Dasher::CControlManager::CTL_USER + iControlOffset, -2);
1138 // }
1139 // else {
1140 // for(int i(0); i < iNSub; ++i) {
1141 // gtk_dasher_control_register_node( GTK_DASHER_CONTROL(pDasherWidget), Dasher::CControlManager::CTL_USER + iControlOffset + i + 1, dasher_action_get_sub_name(pCurrentAction->pAction, i), -1 );
1142 // gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pDasherWidget), Dasher::CControlManager::CTL_USER + iControlOffset + i + 1, Dasher::CControlManager::CTL_USER + iControlOffset, -2);
1143 // gtk_dasher_control_connect_node( GTK_DASHER_CONTROL(pDasherWidget), -1, Dasher::CControlManager::CTL_USER + iControlOffset + i + 1, -2);
1144 // }
1145 // }
1147 // pCurrentAction->iControlID = Dasher::CControlManager::CTL_USER + iControlOffset;
1148 // pCurrentAction->iNSub = iNSub;
1149 // iControlOffset += iNSub + 1;
1150 // }
1152 // pCurrentAction = pCurrentAction->pNext;
1153 // }
1155 #ifndef WITH_MAEMOFULLSCREEN
1156 // dasher_editor_internal_rebuild_action_pane(pSelf);
1157 #endif
1160 static void
1161 dasher_editor_internal_add_action(DasherEditor *pSelf, DasherAction *pNewAction) {
1162 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1164 EditorAction *pNewEditorAction = new EditorAction;
1165 pNewEditorAction->pAction = pNewAction;
1166 pNewEditorAction->iID = pPrivate->iNextActionID;
1167 ++pPrivate->iNextActionID;
1169 gchar szRegistryName[256];
1170 strncpy(szRegistryName, "Action_", 256);
1171 strncat(szRegistryName, dasher_action_get_name(pNewEditorAction->pAction), 255 - strlen(szRegistryName));
1173 for(unsigned int i(0); i < strlen(szRegistryName); ++i)
1174 if(szRegistryName[i] == ' ')
1175 szRegistryName[i] = '_';
1177 gint iState;
1179 if(!dasher_app_settings_get_free_long(pPrivate->pAppSettings, szRegistryName, iState)) {
1180 if(!strcmp(dasher_action_get_name(pNewEditorAction->pAction), "Speak"))
1181 iState = 0;
1182 else
1183 iState = ACTION_STATE_SHOW | ACTION_STATE_CONTROL;
1185 dasher_app_settings_set_free_long(pPrivate->pAppSettings, szRegistryName, iState);
1188 pNewEditorAction->bShow = iState & ACTION_STATE_SHOW;
1189 pNewEditorAction->bControl = iState & ACTION_STATE_CONTROL;
1190 pNewEditorAction->bAuto = iState & ACTION_STATE_AUTO;
1192 dasher_editor_internal_check_activity(pSelf, pNewEditorAction);
1194 if(pPrivate->pActionRing) {
1195 pNewEditorAction->pNext = pPrivate->pActionRing;
1196 pNewEditorAction->pPrevious = pPrivate->pActionRing->pPrevious;
1197 pPrivate->pActionRing->pPrevious->pNext = pNewEditorAction;
1198 pPrivate->pActionRing->pPrevious = pNewEditorAction;
1200 else {
1201 pNewEditorAction->pNext = pNewEditorAction;
1202 pNewEditorAction->pPrevious = pNewEditorAction;
1205 pPrivate->pActionRing = pNewEditorAction;
1207 // TODO: Reimplement
1208 // if(iState & ACTION_STATE_SHOW)
1209 // gtk_dasher_control_add_action_button(GTK_DASHER_CONTROL(pDasherWidget), dasher_action_get_name(pNewEditorAction->pAction));
1212 static EditorAction *
1213 dasher_editor_internal_get_action_by_id(DasherEditor *pSelf, int iID){
1214 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1216 EditorAction *pCurrentAction = pPrivate->pActionRing;
1217 bool bStarted = false;
1219 while(!bStarted || (pCurrentAction != pPrivate->pActionRing)) {
1220 bStarted = true;
1221 if(pCurrentAction->iID == iID)
1222 return pCurrentAction;
1223 pCurrentAction = pCurrentAction->pNext;
1226 return 0;
1229 static void
1230 dasher_editor_internal_rebuild_action_pane(DasherEditor *pSelf) {
1231 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1233 // Delete any existing widgets
1234 gtk_container_foreach(GTK_CONTAINER(pPrivate->pActionPane), delete_children_callback, 0);
1236 // Add the cancel button
1237 GtkButton *pNewButton = GTK_BUTTON(gtk_button_new_with_label("Clear"));
1238 gtk_widget_show(GTK_WIDGET(pNewButton));
1240 void **pUserData = new void *[2];
1241 pUserData[0] = (void *)pSelf;
1242 pUserData[1] = 0;
1244 g_signal_connect(G_OBJECT(pNewButton), "clicked", G_CALLBACK(action_button_callback), pUserData);
1245 #ifdef WITH_MAEMO
1246 // For Maemo we want the packing to expand
1247 gtk_box_pack_start(GTK_BOX(pPrivate->pActionPane), GTK_WIDGET(pNewButton), true, true, 0);
1248 #else
1249 gtk_box_pack_start(GTK_BOX(pPrivate->pActionPane), GTK_WIDGET(pNewButton), false, false, 0);
1250 #endif
1253 EditorAction *pCurrentAction = pPrivate->pActionRing;
1254 bool bStarted = false;
1256 while(!bStarted || (pCurrentAction != pPrivate->pActionRing)) {
1257 bStarted = true;
1258 if(pCurrentAction->bShow) {
1259 GtkButton *pNewButton = GTK_BUTTON(gtk_button_new_with_label(dasher_action_get_name(pCurrentAction->pAction)));
1260 gtk_widget_show(GTK_WIDGET(pNewButton));
1262 pUserData = new void *[2];
1263 pUserData[0] = (void *)pSelf;
1264 pUserData[1] = (void *)(pCurrentAction->pAction);
1266 g_signal_connect(G_OBJECT(pNewButton), "clicked", G_CALLBACK(action_button_callback), pUserData);
1267 #ifdef WITH_MAEMO
1268 // For Maemo we want the packing to expand
1269 gtk_box_pack_start(GTK_BOX(pPrivate->pActionPane), GTK_WIDGET(pNewButton), true, true, 0);
1270 #else
1271 gtk_box_pack_start(GTK_BOX(pPrivate->pActionPane), GTK_WIDGET(pNewButton), false, false, 0);
1272 #endif
1274 pCurrentAction = pCurrentAction->pNext;
1278 // TODO: This shouldn't be a part of the editor
1279 //static void
1280 //dasher_editor_internal_display_message(DasherEditor *pSelf, DasherMessageInfo *pMessageInfo) {
1281 // GtkMessageDialog *pDialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(0, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, pMessageInfo->szMessage));
1282 // gtk_dialog_run(GTK_DIALOG(pDialog));
1283 // gtk_widget_destroy(GTK_WIDGET(pDialog));
1286 static void
1287 dasher_editor_internal_check_activity(DasherEditor *pSelf, EditorAction *pAction) {
1288 gboolean bNeedActive(pAction->bShow || pAction->bControl || pAction->bAuto);
1289 gboolean bActive(dasher_action_get_active(pAction->pAction));
1291 if(bNeedActive && !bActive)
1292 dasher_action_activate(pAction->pAction);
1293 else if(!bNeedActive && bActive)
1294 dasher_action_deactivate(pAction->pAction);
1297 static void
1298 dasher_editor_internal_action_save_state(DasherEditor *pSelf, EditorAction *pAction) {
1299 gchar szRegistryName[256];
1300 strncpy(szRegistryName, "Action_", 256);
1301 strncat(szRegistryName, dasher_action_get_name(pAction->pAction), 255 - strlen(szRegistryName));
1303 for(unsigned int i(0); i < strlen(szRegistryName); ++i)
1304 if(szRegistryName[i] == ' ')
1305 szRegistryName[i] = '_';
1307 gint iState = 0;
1309 if(pAction->bShow)
1310 iState += ACTION_STATE_SHOW;
1312 if(pAction->bControl)
1313 iState += ACTION_STATE_CONTROL;
1315 if(pAction->bAuto)
1316 iState += ACTION_STATE_AUTO;
1318 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1319 dasher_app_settings_set_free_long(pPrivate->pAppSettings, szRegistryName, iState);
1322 static void
1323 dasher_editor_internal_command_new(DasherEditor *pSelf) {
1324 dasher_editor_internal_new_buffer(pSelf, NULL);
1327 static void
1328 dasher_editor_internal_command_open(DasherEditor *pSelf) {
1329 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1331 GtkWidget *pTopLevel = gtk_widget_get_toplevel(GTK_WIDGET(pPrivate->pTextView));
1332 GtkWidget *filesel = gtk_file_chooser_dialog_new(_("Select File"),
1333 GTK_WINDOW(pTopLevel),
1334 GTK_FILE_CHOOSER_ACTION_OPEN,
1335 GTK_STOCK_OPEN,
1336 GTK_RESPONSE_ACCEPT,
1337 GTK_STOCK_CANCEL,
1338 GTK_RESPONSE_CANCEL, NULL);
1340 #ifdef HAVE_GIO
1341 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(filesel), FALSE);
1342 #endif
1344 if(gtk_dialog_run(GTK_DIALOG(filesel)) == GTK_RESPONSE_ACCEPT) {
1345 #ifdef HAVE_GIO
1346 char *filename = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(filesel));
1347 #else
1348 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filesel));
1349 #endif
1350 dasher_editor_internal_new_buffer(pSelf, filename);
1351 g_free(filename);
1354 gtk_widget_destroy(filesel);
1357 static void
1358 dasher_editor_internal_command_save(DasherEditor *pSelf, gboolean bPrompt, gboolean bAppend) {
1359 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1361 gchar *szFilename = NULL;
1363 // Hmm... this makes no sense - surely this always evaluates to true?
1364 if(bPrompt || !szFilename) {
1365 GtkWidget *pTopLevel = gtk_widget_get_toplevel(GTK_WIDGET(pPrivate->pTextView));
1366 GtkWidget *filesel = gtk_file_chooser_dialog_new(_("Select File"),
1367 GTK_WINDOW(pTopLevel),
1368 GTK_FILE_CHOOSER_ACTION_SAVE,
1369 GTK_STOCK_SAVE,
1370 GTK_RESPONSE_ACCEPT,
1371 GTK_STOCK_CANCEL,
1372 GTK_RESPONSE_CANCEL, NULL);
1374 #ifdef HAVE_GIO
1375 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(filesel), FALSE);
1376 #endif
1378 if(gtk_dialog_run(GTK_DIALOG(filesel)) == GTK_RESPONSE_ACCEPT) {
1379 #ifdef HAVE_GIO
1380 szFilename = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(filesel));
1381 #else
1382 szFilename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filesel));
1383 #endif
1385 else {
1386 gtk_widget_destroy(filesel);
1387 return;
1390 gtk_widget_destroy(filesel);
1392 else {
1393 szFilename = g_strdup(pPrivate->szFilename);
1396 dasher_editor_internal_save_as(pSelf, szFilename, bAppend);
1397 g_free(szFilename);
1400 #ifdef HAVE_GIO
1401 static void
1402 dasher_editor_internal_gvfs_print_error(DasherEditor *pSelf, GError *error, const char *myfilename) {
1403 // Turns a GVFS error into English
1404 GtkWidget *error_dialog;
1405 // error_dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Could not open the file \"%s\"\n%s\n", myfilename, gnome_vfs_result_to_string(*result));
1406 error_dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Could not open the file \"%s\"\n%s\n", myfilename, error->message);
1407 gtk_dialog_set_default_response(GTK_DIALOG(error_dialog), GTK_RESPONSE_OK);
1408 gtk_window_set_resizable(GTK_WINDOW(error_dialog), FALSE);
1409 gtk_dialog_run(GTK_DIALOG(error_dialog));
1410 gtk_widget_destroy(error_dialog);
1411 return;
1414 static gboolean
1415 dasher_editor_internal_gvfs_open_file(DasherEditor *pSelf, const char *uri, gchar **buffer, gsize *size)
1417 GFile *file;
1418 GFileInputStream *read_handle;
1419 GError *error;
1420 GFileInfo *info;
1421 gssize bytes_read;
1423 file = g_file_new_for_uri (uri);
1425 read_handle = g_file_read (file, NULL, &error);
1427 /* If URI didn't work, try path */
1428 if (read_handle == NULL)
1429 { // PRLW: g_object_unref isn't actually stipulated by g_file_new_for_uri
1430 g_object_unref (file);
1431 file = g_file_new_for_path (uri);
1432 read_handle = g_file_read (file, NULL, &error);
1435 if (read_handle == NULL)
1437 dasher_editor_internal_gvfs_print_error (pSelf, error, uri);
1438 g_object_unref (file);
1439 return FALSE;
1442 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
1443 G_FILE_QUERY_INFO_NONE, NULL, &error);
1445 if (info == NULL)
1447 dasher_editor_internal_gvfs_print_error (pSelf, error, uri);
1448 g_input_stream_close (G_INPUT_STREAM(read_handle), NULL, &error);
1449 g_object_unref (read_handle);
1450 g_object_unref (file);
1451 return FALSE;
1454 // XXX PRLW: cases info > max(size) as max(size) < max(uint64),
1455 // and bytes_read < size aren't handled.
1456 *size = g_file_info_get_attribute_uint64(info,G_FILE_ATTRIBUTE_STANDARD_SIZE);
1457 *buffer = (gchar *) g_malloc (*size);
1458 bytes_read = g_input_stream_read (G_INPUT_STREAM(read_handle), *buffer,
1459 *size, NULL, &error);
1461 if (bytes_read == -1)
1463 dasher_editor_internal_gvfs_print_error (pSelf, error, uri);
1464 g_input_stream_close (G_INPUT_STREAM(read_handle), NULL, &error);
1465 g_object_unref (read_handle);
1466 g_object_unref (info);
1467 g_object_unref (file);
1468 return FALSE;
1471 g_input_stream_close (G_INPUT_STREAM(read_handle), NULL, NULL);
1472 g_object_unref (read_handle);
1473 g_object_unref (info);
1474 g_object_unref (file);
1475 return TRUE;
1478 static GFileOutputStream *append_or_replace_file(GFile *file, bool append, GError **error)
1480 GFileOutputStream *write_handle;
1481 if (append)
1482 write_handle = g_file_append_to (file, G_FILE_CREATE_NONE, NULL, error);
1483 else
1484 write_handle = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE,
1485 NULL, error);
1487 return write_handle;
1490 static gboolean
1491 dasher_editor_internal_gvfs_save_file(DasherEditor *pSelf, const char *uri, gchar *buffer, gsize length, bool append)
1493 GFile *file;
1494 GFileOutputStream *write_handle;
1495 GError *error;
1496 gssize bytes_written;
1498 file = g_file_new_for_uri (uri);
1500 write_handle = append_or_replace_file (file, append, &error);
1502 /* If URI didn't work, try path */
1503 if (write_handle == NULL)
1505 g_object_unref (file);
1506 file = g_file_new_for_path (uri);
1507 write_handle = append_or_replace_file (file, append, &error);
1510 if (write_handle == NULL)
1512 dasher_editor_internal_gvfs_print_error (pSelf, error, uri);
1513 g_object_unref (file);
1514 return FALSE;
1517 if (append)
1519 if (!g_seekable_seek(G_SEEKABLE(write_handle),0,G_SEEK_END, NULL, &error))
1521 dasher_editor_internal_gvfs_print_error (pSelf, error, uri);
1522 g_object_unref (write_handle);
1523 g_object_unref (file);
1524 return FALSE;
1528 bytes_written = g_output_stream_write (G_OUTPUT_STREAM(write_handle), buffer,
1529 length, NULL, &error);
1530 // XXX PRLW: case bytes_written < length not handled.
1531 if (bytes_written == -1)
1533 dasher_editor_internal_gvfs_print_error (pSelf, error, uri);
1534 g_output_stream_close (G_OUTPUT_STREAM(write_handle), NULL, NULL);
1535 g_object_unref (write_handle);
1536 g_object_unref (file);
1537 return FALSE;
1540 g_output_stream_close (G_OUTPUT_STREAM(write_handle), NULL, NULL);
1541 g_object_unref (write_handle);
1542 g_object_unref (file);
1543 return TRUE;
1546 #else /* not HAVE_GIO */
1548 static gboolean
1549 dasher_editor_internal_unix_vfs_open_file(DasherEditor *pSelf, const char *myfilename, gchar **buffer, gsize *size) {
1550 GtkWidget *error_dialog;
1552 struct stat file_stat;
1553 FILE *fp;
1555 stat(myfilename, &file_stat);
1556 fp = fopen(myfilename, "r");
1558 if(fp == NULL || S_ISDIR(file_stat.st_mode)) {
1559 // error_dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Could not open the file \"%s\".\n", myfilename);
1560 error_dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Could not open the file \"%s\".\n", myfilename);
1561 gtk_dialog_set_default_response(GTK_DIALOG(error_dialog), GTK_RESPONSE_OK);
1562 gtk_window_set_resizable(GTK_WINDOW(error_dialog), FALSE);
1563 gtk_dialog_run(GTK_DIALOG(error_dialog));
1564 gtk_widget_destroy(error_dialog);
1565 return FALSE;
1568 *size = file_stat.st_size; // PRLW: is off_t = uint64_t, size is size_t, MD
1569 *buffer = (gchar *) g_malloc(*size);
1570 fread(*buffer, *size, 1, fp);
1571 fclose(fp);
1572 return TRUE;
1575 static gboolean
1576 dasher_editor_internal_unix_vfs_save_file(DasherEditor *pSelf, const char *myfilename, gchar *buffer, gsize length, bool append) {
1577 int opened = 1;
1578 GtkWidget *error_dialog;
1580 FILE *fp;
1582 if(append == true) {
1583 fp = fopen(myfilename, "a");
1585 if(fp == NULL) {
1586 opened = 0;
1589 else {
1590 fp = fopen(myfilename, "w");
1591 if(fp == NULL) {
1592 opened = 0;
1596 if(!opened) {
1597 // error_dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Could not save the file \"%s\".\n", myfilename);
1598 error_dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Could not save the file \"%s\".\n", myfilename);
1599 gtk_dialog_set_default_response(GTK_DIALOG(error_dialog), GTK_RESPONSE_OK);
1600 gtk_window_set_resizable(GTK_WINDOW(error_dialog), FALSE);
1601 gtk_dialog_run(GTK_DIALOG(error_dialog));
1602 gtk_widget_destroy(error_dialog);
1603 return false;
1606 fwrite(buffer, 1, length, fp);
1607 fclose(fp);
1608 return true;
1610 #endif
1612 static void
1613 dasher_editor_internal_set_filename(DasherEditor *pSelf, const gchar *szFilename) {
1614 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1616 if(pPrivate->szFilename)
1617 g_free((void *)pPrivate->szFilename);
1619 if(szFilename)
1620 pPrivate->szFilename = g_strdup(szFilename);
1621 else
1622 pPrivate->szFilename = NULL;
1624 g_signal_emit_by_name(G_OBJECT(pSelf), "filename_changed", G_OBJECT(pSelf), NULL, NULL);
1627 static void
1628 dasher_editor_internal_convert(DasherEditor *pSelf) {
1629 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1631 if(pPrivate->pBufferSet)
1632 idasher_buffer_set_edit_convert(pPrivate->pBufferSet);
1635 static void
1636 dasher_editor_internal_protect(DasherEditor *pSelf) {
1637 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1639 if(pPrivate->pBufferSet)
1640 idasher_buffer_set_edit_protect(pPrivate->pBufferSet);
1643 static void
1644 dasher_editor_internal_new_buffer(DasherEditor *pSelf, const gchar *szFilename) {
1645 /* TODO: eventually rewrite this without references to external functions */
1647 if(szFilename) {
1648 dasher_editor_internal_open(pSelf, szFilename);
1650 else {
1651 dasher_editor_internal_generate_filename(pSelf);
1652 dasher_editor_internal_clear(pSelf, false);
1655 // g_signal_emit_by_name(G_OBJECT(pSelf), "buffer_changed", G_OBJECT(pSelf), NULL, NULL);
1658 static void
1659 dasher_editor_internal_handle_parameter_change(DasherEditor *pSelf, gint iParameter) {
1660 DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
1662 switch(iParameter) {
1663 case APP_SP_EDIT_FONT:
1664 dasher_editor_internal_handle_font(pSelf,
1665 dasher_app_settings_get_string(pPrivate->pAppSettings, APP_SP_EDIT_FONT));
1666 break;
1670 /* Callback Functions */
1672 extern "C" void
1673 delete_children_callback(GtkWidget *pWidget, gpointer pUserData) {
1674 gtk_widget_destroy(pWidget);
1677 extern "C" void
1678 main_window_realized(DasherMain *pMain, gpointer pUserData) {
1681 extern "C" void
1682 action_button_callback(GtkWidget *pWidget, gpointer pUserData) {
1683 void **pPointers((void **)pUserData);
1684 dasher_editor_internal_action_button((DasherEditor *)pPointers[0], (DasherAction *)pPointers[1]);
1687 extern "C" void
1688 context_changed_handler(GObject *pSource, gpointer pUserData) {
1689 DasherEditorInternal *pSelf = DASHER_EDITOR_INTERNAL(pUserData);
1691 // TODO: plumb signal back into control
1692 g_signal_emit_by_name(G_OBJECT(pSelf), "context_changed", G_OBJECT(pSelf), NULL, NULL);
1696 extern "C" void
1697 buffer_changed_handler(GObject *pSource, gpointer pUserData) {
1698 DasherEditorInternal *pSelf = DASHER_EDITOR_INTERNAL(pUserData);
1700 // TODO: plumb signal back into control
1701 g_signal_emit_by_name(G_OBJECT(pSelf), "buffer_changed", G_OBJECT(pSelf), NULL, NULL);