/**
* erwin - really simple html editor
* Copyright (C) 1999 David Vogler
* Copyright (C) 1999-2005 Adrian Reber
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: erwinfunctions.c,v 1.44 2005/01/19 21:07:55 adrian Exp $
*
* $Author: adrian $
*
* Description: a lot of functions
*
* $Log: erwinfunctions.c,v $
* Revision 1.44 2005/01/19 21:07:55 adrian
* update to use the new save_file function
*
* Revision 1.43 2004/12/29 20:08:04 adrian
* * removed functions for old search dialog
* * our buffer changed handler should be called last
*
* Revision 1.42 2004/12/26 21:37:13 adrian
* * finished porting to gtkhtml3
* * fix for bug #11 (now scrolling to found text)
* * moved search functions to searchbar.c
*
* Revision 1.41 2004/12/20 20:09:46 adrian
* * removed USE_GTKHTML ifdefs
* * started porting erwin to gtkhtml3
*
* Revision 1.40 2004/10/26 19:00:30 erwin
* searchbar version 1 done
*
* Revision 1.39 2004/10/03 20:18:01 erwin
* more searchbar related changes
*
* Revision 1.38 2004/09/26 21:07:00 erwin
* - more work on the searchbar
*
* Revision 1.37 2004/07/03 20:14:25 erwin
* commit
*
* Revision 1.36 2004/06/27 17:48:24 erwin
* * added drag'n'drop support
* * bug fixes
* * optimized statusbar handling
* * removed unused code
* * changed search functions to use gtk_source_iter_forward_search()
* * better
*
* Revision 1.35 2004/06/21 21:45:19 erwin
* big commit
* it has been a long time without a checkout
* we are close to version 0.7
*
* Revision 1.34 2004/03/21 21:06:30 erwin
* support for gtk 2.4 GtkFileChooserDialog
*
* Revision 1.33 2004/03/11 21:05:01 erwin
* too many changes without commits
*
* Revision 1.32 2003/11/18 08:52:24 erwin
* fix message dialogs
*
* Revision 1.31 2003/10/30 20:54:06 erwin
* syntax highlighting implementation
*
* Revision 1.30 2003/10/24 13:31:44 erwin
* more syntax higlighting related stuff
*
* Revision 1.29 2003/10/22 15:21:35 erwin
* include file mess cleaned up
* changed format to indent -kr -i8 -l100
* gtksourceview support
* using the GtkMessageWidget with stock icons
*
*/
#ifndef lint
static const char vcid[] = "$Id: erwinfunctions.c,v 1.44 2005/01/19 21:07:55 adrian Exp $";
#endif /* lint */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
extern GtkWidget *main_window;
extern struct font_options font_options;
extern GtkWidget *status_bar;
gint changed = 1;
gint from_beginning = 0;
gint close_notebook = -1;
GtkTextBuffer *get_text_buffer()
{
struct document *document;
GtkTextBuffer *buffer;
if (nr_of_documents == -1)
return NULL;
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
if (document->is_rendered)
return NULL;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(document->text_view));
_DEBUG_ fprintf(stderr, "%s:get_text_buffer:%p\n", PACKAGE, buffer);
return buffer;
}
int count_characters(GtkTextBuffer * buffer)
{
return gtk_text_buffer_get_char_count(buffer);
}
void update_statistic(GtkTextBuffer * buffer)
{
gchar length[64];
gint chars;
if (globals.display_statistic) {
chars = count_characters(buffer);
if (chars == 1)
snprintf(length, 63, "%d character", chars);
else
snprintf(length, 63, "%d characters", chars);
add_to_statusbar(length, FALSE);
}
}
void clean_buffer()
{
GtkTextBuffer *buffer;
GtkTextIter start, end;
buffer = get_text_buffer();
gtk_text_buffer_get_start_iter(buffer, &start);
gtk_text_buffer_get_end_iter(buffer, &end);
gtk_text_buffer_delete(buffer, &start, &end);
}
void focus_text_view()
{
struct document *document;
if (rendered())
return;
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
gtk_window_set_focus(GTK_WINDOW(main_window), document->text_view);
}
gboolean rendered()
{
struct document *document;
if (nr_of_documents == -1)
return TRUE;
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
_DEBUG_ fprintf(stderr, "rendered:%d\n", document->is_rendered);
return document->is_rendered;
}
void clean_selected()
{
GtkTextBuffer *buffer;
GtkTextIter start, end;
buffer = get_text_buffer();
if (gtk_text_buffer_get_selection_bounds(buffer, &start, &end)) {
gtk_text_buffer_delete(buffer, &start, &end);
}
}
void insert_text(char *string, gint length)
{
GtkTextBuffer *buffer;
struct document *document;
if (!length)
return;
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(document->text_view));
gtk_text_buffer_create_tag(buffer, NULL, NULL);
document->changed = TRUE;
gtk_text_buffer_insert_at_cursor(buffer, string, length);
}
void insert_text_around(struct change change, char *string, gint length)
{
gchar *buffer;
gchar *another_buffer;
gint i = 0;
struct change help;
struct document *document;
GtkTextBuffer *g_buffer;
GtkTextIter start, end;
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
document->changed = TRUE;
g_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(document->text_view));
help = change;
/*now filling another_buffer with the starting tag */
another_buffer = g_malloc(length + 9);
another_buffer[0] = '<';
for (i = 1; i < length + 1; i++)
another_buffer[i] = string[i - 1];
another_buffer[length + 1] = '>';
another_buffer[length + 2] = '\0';
gtk_text_buffer_get_iter_at_offset(g_buffer, &start, change.start);
gtk_text_buffer_get_iter_at_offset(g_buffer, &end, change.end);
buffer = gtk_text_buffer_get_text(g_buffer, &start, &end, FALSE);
gtk_text_buffer_delete(g_buffer, &start, &end);
gtk_text_buffer_insert(g_buffer, &start, another_buffer, -1);
gtk_text_buffer_insert(g_buffer, &start, buffer, -1);
/*now filling another_buffer with the ending tag */
another_buffer[0] = '<';
another_buffer[1] = '/';
for (i = 2; i < length + 2; i++)
another_buffer[i] = string[i - 2];
another_buffer[length + 2] = '>';
another_buffer[length + 3] = '\0';
gtk_text_buffer_insert(g_buffer, &start, another_buffer, -1);
move_cursor(length + 3, LEFT);
g_free(buffer);
g_free(another_buffer);
_DEBUG_ fprintf(stderr, "%s:insert_text_around ends\n", PACKAGE);
}
void copy_to_clipboard(GtkWidget * window)
{
if (rendered())
return;
gtk_text_buffer_copy_clipboard(get_text_buffer(), globals.clipboard);
}
void cut_to_clipboard(GtkWidget * window)
{
if (rendered())
return;
gtk_text_buffer_cut_clipboard(get_text_buffer(), globals.clipboard, TRUE);
}
void paste_from_clipboard(GtkWidget * window)
{
if (rendered())
return;
gtk_text_buffer_paste_clipboard(get_text_buffer(), globals.clipboard, NULL, TRUE);
}
struct change test_selection()
{
struct change change;
gint help = 0;
GtkTextBuffer *buffer;
GtkTextIter start, end;
buffer = get_text_buffer();
if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end)) {
_DEBUG_ fprintf(stderr, "%s:now no selection is made\n", PACKAGE);
_DEBUG_ fprintf(stderr, "%s:start: %d:end: %d\n", PACKAGE,
gtk_text_iter_get_offset(&start), gtk_text_iter_get_offset(&end));
help = gtk_text_iter_get_offset(&start);
change.start = change.end = help;
} else {
_DEBUG_ fprintf(stderr, "%s:now a selection is made\n", PACKAGE);
_DEBUG_ fprintf(stderr, "%s:start: %d:end: %d\n", PACKAGE,
gtk_text_iter_get_offset(&start), gtk_text_iter_get_offset(&end));
change.start = 0;
change.end = 0;
change.start = gtk_text_iter_get_offset(&start);
change.end = gtk_text_iter_get_offset(&end);
if (change.start > change.end) {
help = change.start;
change.start = change.end;
change.end = help;
}
}
_DEBUG_ fprintf(stderr, "%s:change.start:%d:change.end:%d\n", PACKAGE, change.start,
change.end);
return change;
}
gint move_cursor(gint length, ErwinCursor orientation)
{
//gtk_text_iter_backward_visible_cursor_positions and
//gtk_text_iter_forward_visible_cursor_positions could be used here
//but current implementation seems to work quite good and
//therefore it will not be changed
struct change change;
GtkTextIter iter, iter2, start, end;
GtkTextBuffer *buffer = NULL;
buffer = get_text_buffer();
gtk_text_buffer_get_start_iter(buffer, &start);
gtk_text_buffer_get_start_iter(buffer, &iter);
gtk_text_buffer_get_start_iter(buffer, &iter2);
gtk_text_buffer_get_end_iter(buffer, &end);
change = test_selection();
gtk_text_iter_set_offset(&iter, change.start);
gtk_text_iter_set_offset(&iter2, change.start + length);
_DEBUG_ fprintf(stderr, "%s:now moving cursor: %d\n", PACKAGE, length);
if (orientation == LEFT) {
if (((change.start - length) <= 0) || (length == -1))
gtk_text_buffer_place_cursor(buffer, &start);
else {
gtk_text_iter_set_offset(&start, change.start - length);
gtk_text_buffer_place_cursor(buffer, &start);
}
_DEBUG_ fprintf(stderr, "%s:LEFT:position is %d\n", PACKAGE, change.start);
}
if (orientation == RIGHT) {
if ((gtk_text_iter_compare(&iter2, &end) >= 0) || (length == -1))
gtk_text_buffer_place_cursor(buffer, &end);
else {
_DEBUG_ fprintf(stderr, "%s:moving cursor right\n", PACKAGE);
gtk_text_iter_set_offset(&end, change.start + length);
gtk_text_buffer_place_cursor(buffer, &end);
}
_DEBUG_ fprintf(stderr, "%s:RIGHT:position is %d\n", PACKAGE, change.start);
} else
return 42;
return 0;
}
void file_ok_sel(GtkWidget * widget, GtkFileSelection * fs)
{
GString *only_the_file;
only_the_file = g_string_new("
");
insert_text(only_the_file->str, only_the_file->len);
move_cursor(only_the_file->len, RIGHT);
g_string_free(only_the_file, TRUE);
gtk_widget_destroy(GTK_WIDGET(fs));
}
void img_functions(GtkWidget * window)
{
GtkWidget *filew;
if (rendered())
return;
filew = gtk_file_selection_new("Image File selection");
gtk_signal_connect(GTK_OBJECT(filew), "destroy", (GtkSignalFunc) destroy_message, &filew);
gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filew)->ok_button),
"clicked", (GtkSignalFunc) file_ok_sel, filew);
gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(filew)->
cancel_button), "clicked",
(GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT(filew));
/*gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), "nothing"); */
gtk_widget_show(filew);
}
void get_value_1(GtkWidget * widget, GtkWidget * spinner)
{
GtkSpinButton *spin;
spin = GTK_SPIN_BUTTON(spinner);
table_values.rows = gtk_spin_button_get_value_as_int(spin);
_DEBUG_ fprintf(stderr, "%s:spin button: %d\n", PACKAGE,
gtk_spin_button_get_value_as_int(spin));
}
void get_value_2(GtkWidget * widget, GtkWidget * spinner)
{
GtkSpinButton *spin;
spin = GTK_SPIN_BUTTON(spinner);
table_values.cols = gtk_spin_button_get_value_as_int(spin);
_DEBUG_ fprintf(stderr, "%s:spin button: %d\n", PACKAGE,
gtk_spin_button_get_value_as_int(spin));
}
void quit_program_from_menu()
{
quit_program();
}
gboolean quit_program()
{
GtkWidget *dialog;
if (!rendered()) {
if (gtk_text_buffer_get_modified(get_text_buffer())) {
_DEBUG_ fprintf(stderr, "%s:text has been changed after save event\n",
PACKAGE);
dialog = gtk_message_dialog_new(GTK_WINDOW(main_window),
GTK_DIALOG_MODAL |
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL,
"File has not been saved...\nReally want to quit?");
switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
case GTK_RESPONSE_OK:
really_quit_program();
//never reached???
_DEBUG_ fprintf(stderr, "%s:never reached???\n", PACKAGE);
break;
default:
break;
}
gtk_widget_destroy(dialog);
return TRUE;
}
}
really_quit_program();
return FALSE;
}
void really_quit_program()
{
_DEBUG_ fprintf(stderr, "%s:quit event occured\n", PACKAGE);
the_end();
exit(0);
}
gint delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
{
_DEBUG_ fprintf(stderr, "%s:delete event occured\n", PACKAGE);
return (TRUE);
}
void destroy_message(GtkWidget * dialog)
{
gtk_grab_remove(dialog);
gtk_widget_destroy(dialog);
}
void destroy_table_wizard(GtkWidget * dialog)
{
gint i = 1, ii = 1;
gchar *buffer = NULL;
GtkTextIter start, end;
clean_selected();
gtk_text_buffer_get_selection_bounds(get_text_buffer(), &start, &end);
gtk_text_buffer_get_end_iter(get_text_buffer(), &end);
buffer = gtk_text_buffer_get_text(get_text_buffer(), &start, &end, FALSE);
gtk_text_buffer_delete(get_text_buffer(), &start, &end);
insert_text("\n\n", 9);
move_cursor(9, RIGHT);
for (i = 1; i <= table_values.rows; i++) {
insert_text("\n", 5);
move_cursor(5, RIGHT);
for (ii = 1; ii <= table_values.cols; ii++) {
insert_text("\t | \n", 11);
if (ii != table_values.cols || ii == 1) {
move_cursor(11, RIGHT);
} else {
move_cursor(4, RIGHT);
}
if (table_values.cols == 1 && table_values.rows != 1) {
move_cursor(1, LEFT);
insert_text("\n", 1);
if (i == table_values.rows) {
move_cursor(7, RIGHT);
insert_text("\n", 1);
move_cursor(1, RIGHT);
}
}
if (i != table_values.rows && ii == table_values.cols) {
move_cursor(8, RIGHT);
}
if (ii == table_values.cols) {
move_cursor(15, RIGHT);
}
if (table_values.rows != 1 && table_values.cols != 1
&& ii == table_values.cols) {
move_cursor(4, RIGHT);
if (i != table_values.rows) {
insert_text("\n", 1);
move_cursor(1, RIGHT);
} else {
move_cursor(7, RIGHT);
insert_text("\n", 1);
move_cursor(1, RIGHT);
}
}
}
insert_text("
\n", 6);
}
insert_text("
\n", 9);
gtk_text_buffer_get_end_iter(get_text_buffer(), &end);
gtk_text_buffer_insert(get_text_buffer(), &end, buffer, -1);
g_free(buffer);
gtk_grab_remove(dialog);
gtk_widget_destroy(dialog);
}
void make_highlighted_text_view(struct document *document, GtkTextBuffer * buffer)
{
GSList *languages = NULL;
gpointer blub;
int i = 0;
document->manager = gtk_source_languages_manager_new();
g_object_ref(document->manager);
g_object_set_data_full(G_OBJECT(buffer), "languages-manager",
document->manager, (GDestroyNotify) g_object_unref);
document->manager = g_object_get_data(G_OBJECT(buffer), "languages-manager");
languages =
(GSList *) gtk_source_languages_manager_get_available_languages(document->manager);
while ((blub = g_slist_nth_data(languages, i++))) {
if (globals.default_highlighting
&& !strcmp(globals.default_highlighting, gtk_source_language_get_name(blub)))
document->language = blub;
}
g_object_set(G_OBJECT(buffer), "highlight", TRUE, NULL);
g_object_get(G_OBJECT(buffer), "highlight", &(document->syntax_highlighting), NULL);
gtk_source_buffer_set_language(GTK_SOURCE_BUFFER(buffer), document->language);
if (document->syntax_highlighting)
add_to_statusbar(gtk_source_language_get_name(document->language), TRUE);
else
add_to_statusbar(NULL, TRUE);
}
void _open_file_ok(const gchar * filename)
{
GtkWidget *scrollbar;
struct document *document;
gchar erwin[1025];
FILE *fd = NULL;
GtkTextBuffer *buffer;
GtkTextIter end;
gboolean open = TRUE;
GtkWidget *label_box;
GtkWidget *image;
GtkWidget *button;
gint display_statistic = globals.display_statistic;
gboolean only_open = FALSE;
if (!filename)
open = FALSE;
if (open) {
fd = fopen(filename, "r");
_DEBUG_ fprintf(stderr, "%s:filename is set to: %s", PACKAGE, filename);
//strcpy(file, filename);
if (fd == NULL) {
_DEBUG_ fprintf(stderr, "%s:can't open file for reading\n", PACKAGE);
display_dialog("Error", "Insufficient permissions\nto read that file");
return;
}
}
if (nr_of_documents == -1)
gtk_widget_show(GTK_WIDGET(notebook_html));
else {
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
//if it is a new document (meaning no text and changes) and a file open
//no new widget is created
if (document->new_document && open)
only_open = TRUE;
}
if (!only_open) {
document = g_malloc(sizeof(struct document));
memset(document, 0, sizeof(struct document));
document->text_view = GTK_WIDGET(gtk_source_view_new());
_DEBUG_ fprintf(stderr, "%s:new 1 text_view : %p\n", PACKAGE, document->text_view);
}
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(document->text_view));
if (open) {
document->filename = g_string_new(filename);
add_to_recent(document->filename->str);
update_recent(NULL);
document->saved = TRUE;
} else {
document->saved = FALSE;
document->filename = g_string_new("Untitled");
}
_DEBUG_ fprintf(stderr, "%s:file %s\n", PACKAGE, document->filename->str);
if (!only_open) {
gtk_text_buffer_create_tag(buffer, "red_background", "background", "red", NULL);
gtk_text_buffer_create_tag(buffer, "yellow_background", "background", "yellow",
NULL);
document->notebook_child = gtk_hbox_new(FALSE, FALSE);
scrollbar = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbar), GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(scrollbar), document->text_view);
gtk_box_pack_start(GTK_BOX(document->notebook_child), scrollbar, TRUE, TRUE, 0);
gtk_widget_show(document->text_view);
gtk_widget_show(scrollbar);
gtk_widget_show(document->notebook_child);
make_dropable(GTK_TEXT_VIEW(document->text_view));
label_box = gtk_hbox_new(FALSE, FALSE);
document->notebook_label = gtk_label_new(NULL);
gtk_widget_show(document->notebook_label);
gtk_box_pack_start(GTK_BOX(label_box), document->notebook_label, TRUE, TRUE, 0);
button = gtk_button_new();
image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
gtk_container_add(GTK_CONTAINER(button), image);
gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
gtk_widget_show(image);
gtk_widget_show(button);
gtk_box_pack_start(GTK_BOX(label_box), button, TRUE, TRUE, 0);
gtk_widget_show(label_box);
document->nr_of_notebook_child = ++nr_of_documents;
document->notebook = notebook_main;
document->close_file = FALSE;
document->is_rendered = FALSE;
document->new_document = TRUE;
documents = g_list_append(documents, document);
make_highlighted_text_view(document, buffer);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook_main), document->notebook_child,
label_box);
gtk_notebook_set_page(GTK_NOTEBOOK(notebook_main), document->nr_of_notebook_child);
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(close_file),
&document->nr_of_notebook_child);
g_signal_connect_after(G_OBJECT(buffer), "changed", G_CALLBACK(buffer_changed),
NULL);
}
gtk_label_set_text(GTK_LABEL(document->notebook_label),
g_basename(document->filename->str));
/* disable updating statusbar */
globals.display_statistic = 0;
if (open) {
activate_highlighting_from_filename(document);
gtk_text_buffer_get_start_iter(buffer, &end);
while (fgets(erwin, 1024, fd) != NULL) {
_DEBUG_ fprintf(stderr, "%s:reading %s", PACKAGE, erwin);
gtk_text_buffer_insert(buffer, &end, erwin, -1);
}
gtk_text_buffer_get_end_iter(buffer, &end);
gtk_text_buffer_get_start_iter(buffer, &end);
gtk_text_buffer_place_cursor(buffer, &end);
gtk_text_buffer_set_modified(buffer, FALSE);
fclose(fd);
document->new_document = FALSE;
} else {
if (globals.show_quickstart)
body_functions();
}
/* revert to previous setting */
globals.display_statistic = display_statistic;
set_title_name();
update_statistic(buffer);
focus_text_view();
}
void open_file_ok(GtkWidget * widget, GtkFileSelection * fs)
{
GString *blubber;
if (nr_of_documents == -1)
gtk_widget_show(GTK_WIDGET(notebook_html));
if (is_file_a_directory(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)))) {
blubber = g_string_new(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
blubber = g_string_append(blubber, "/");
gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), blubber->str);
g_string_free(blubber, TRUE);
return;
}
_open_file_ok(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
gtk_grab_remove(GTK_WIDGET(fs));
gtk_widget_destroy(GTK_WIDGET(fs));
}
void save_file_ok(struct document *document)
{
if (is_file_readonly(document->filename->str)) {
display_dialog("Error", "Insufficient permissions\n to write that file");
return;
}
save_file(NULL, document);
}
void new_file()
{
_open_file_ok(NULL);
}
void close_message_dialog(GtkWidget * widget, gpointer data)
{
GtkWidget *dialog = (GtkWidget *) data;
gtk_widget_destroy(dialog);
}
void ungrab_message(GtkWidget * widget, gpointer data)
{
gtk_grab_remove(widget);
}
void display_dialog(gchar * title, gchar * message)
{
GtkWidget *dialog;
dialog =
gtk_message_dialog_new(GTK_WINDOW(main_window),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO, GTK_BUTTONS_OK, message);
gtk_window_set_title(GTK_WINDOW(dialog), title);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
GtkWidget *entry_in_frame(gchar * title, struct frame_entry *frame_entry)
{
GtkWidget *entry_box;
frame_entry->frame = gtk_frame_new(title);
entry_box = gtk_hbox_new(TRUE, TRUE);
gtk_container_add(GTK_CONTAINER(frame_entry->frame), entry_box);
frame_entry->entry = gtk_entry_new();
gtk_editable_set_editable(GTK_EDITABLE(frame_entry->entry), TRUE);
gtk_widget_show(frame_entry->entry);
gtk_box_pack_start(GTK_BOX(entry_box), frame_entry->entry, FALSE, FALSE, 30);
gtk_widget_show(entry_box);
gtk_widget_show(frame_entry->frame);
return entry_box;
}
void body_functions()
{
body_dialog(body_elements);
}
void legal()
{
GtkWidget *license_text;
GtkWidget *button;
GtkWidget *dialog;
GtkWidget *hbox;
GtkWidget *scroll;
GtkTextBuffer *buffer;
GtkTextIter iter;
dialog = gtk_dialog_new();
gtk_widget_set_usize(GTK_WIDGET(dialog), 650, 300);
gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(ungrab_message), NULL);
gtk_window_set_title(GTK_WINDOW(dialog), "License");
gtk_container_border_width(GTK_CONTAINER(dialog), 3);
button = gtk_button_new_with_label("Make it so!");
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(close_message_dialog),
dialog);
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 0);
license_text = gtk_text_view_new();
scroll = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(scroll), license_text);
gtk_box_pack_start(GTK_BOX(hbox), scroll, TRUE, TRUE, 0);
gtk_text_view_set_editable(GTK_TEXT_VIEW(license_text), FALSE);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(license_text), FALSE);
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(license_text));
gtk_text_buffer_create_tag(buffer, "courier", "family", "courier", NULL);
gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0);
gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, license, -1, "courier", NULL);
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(license_text), 5);
gtk_widget_show(license_text);
gtk_widget_show(scroll);
gtk_widget_show(hbox);
gtk_widget_show(dialog);
gtk_grab_add(dialog);
}
void set_title_name_switch_page(int page_num)
{
GString *title;
struct document *document;
GtkTextBuffer *buffer;
_DEBUG_ fprintf(stderr, "%s:%d\n", PACKAGE, page_num);
if (page_num == -1)
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
else
document = (g_list_nth(documents, page_num))->data;
_DEBUG_ fprintf(stderr, "%s:filename: %s\n", PACKAGE, document->filename->str);
_DEBUG_ fprintf(stderr, "%s:basename: %s\n", PACKAGE, g_basename(document->filename->str));
title = g_string_new(PACKAGE);
title = g_string_append(title, " - ");
if (document->filename->str[0] != 0)
title = g_string_append(title, g_basename(document->filename->str));
else
title = g_string_append(title, "Untitled");
if (!document->is_rendered) {
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(document->text_view));
if (gtk_text_buffer_get_modified(buffer))
title = g_string_append(title, " - *");
}
gtk_window_set_title(GTK_WINDOW(main_window), title->str);
g_string_free(title, TRUE);
}
void set_title_name()
{
set_title_name_switch_page(-1);
}
void buffer_changed(GtkTextBuffer * textbuffer, gpointer user_data)
{
struct document *document;
if (globals.buffer_not_changed) {
gtk_text_buffer_set_modified(get_text_buffer(), FALSE);
return;
}
_DEBUG_ fprintf(stderr, "buffer changed\n");
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
gtk_text_buffer_set_modified(get_text_buffer(), TRUE);
document->new_document = FALSE;
set_title_name();
update_statistic(get_text_buffer());
}
void ok_body_dialog(GtkWidget * widget, gpointer data)
{
gchar *title1 = "\n";
gchar *title2 = "\n";
gchar *title3 = "\n\n\n\n\n\n";
GString *title;
GString *body_options;
int body = 0;
body_options = g_string_new("");
/* Now testing background color */
make_body_options_string(body_options, " bgcolor=\"", &body_elements.bgcolor);
/* Now testing text color */
make_body_options_string(body_options, " text=\"", &body_elements.text);
/* Now testing link color */
make_body_options_string(body_options, " link=\"", &body_elements.link);
/* Now testing vlink color */
make_body_options_string(body_options, " vlink=\"", &body_elements.vlink);
/* Now testing alink color */
make_body_options_string(body_options, " alink=\"", &body_elements.alink);
/* Now testing backgroundimage */
make_body_options_string(body_options, " background=\"", &body_elements.background);
_DEBUG_ fprintf(stderr, "%s:%s:body_elements.title.entry:%s\n", PACKAGE,
__FILE__, (gtk_entry_get_text(GTK_ENTRY(body_elements.title.entry))));
_DEBUG_ fprintf(stderr, "%s:%s:body_elements.bgcolor.entry:%s\n",
PACKAGE, __FILE__,
(gtk_entry_get_text(GTK_ENTRY(body_elements.bgcolor.entry))));
_DEBUG_ fprintf(stderr, "%s:%s:body_elements.text.entry:%s\n", PACKAGE, __FILE__,
(gtk_entry_get_text(GTK_ENTRY(body_elements.text.entry))));
/* Making the string that will be inserted */
title = g_string_new(title1);
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(body_elements.insert_generator)))
title =
g_string_append(title,
"\n ");
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(body_elements.content_type)))
title =
g_string_append(title,
"\n ");
title = g_string_append(title, title2);
title = g_string_append(title, gtk_entry_get_text(GTK_ENTRY(body_elements.title.entry)));
title = g_string_append(title, title3);
title = g_string_append(title, body_options->str);
body = title->len;
title = g_string_append(title, title4);
/* String made... Now inserting */
clean_buffer();
insert_text(title->str, title->len);
move_cursor(-1, LEFT);
move_cursor(body + 1, RIGHT);
/*Freeing memory */
g_string_free(title, TRUE);
g_string_free(body_options, TRUE);
close_body_dialog(NULL, GTK_WIDGET(data));
update_statistic(get_text_buffer());
}
void make_body_options_string(GString * body_options, gchar * text, struct frame_entry *element)
{
if (strcmp("", (gtk_entry_get_text(GTK_ENTRY(element->entry))))) {
body_options = g_string_append(body_options, text);
body_options =
g_string_append(body_options, gtk_entry_get_text(GTK_ENTRY(element->entry)));
body_options = g_string_append(body_options, "\"");
}
}
gboolean does_file_exist(const gchar * filename)
{
struct stat buf;
if (stat(filename, &buf) == -1)
return FALSE;
return TRUE;
}
gboolean is_file_readonly(const gchar * filename)
{
if (strcmp(filename, FILENAME) == 0 || access(filename, F_OK))
return FALSE;
return (access(filename, W_OK) != 0);
}
gboolean is_file_a_directory(const gchar * filename)
{
struct stat buf;
stat(filename, &buf);
if (buf.st_mode & S_IFREG)
return FALSE;
return TRUE;
}
void insert_symmetric_tag(gchar * tag)
{
struct change change;
GString *together;
struct document *document;
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
gtk_text_buffer_set_modified(get_text_buffer(), TRUE);
change = test_selection();
_DEBUG_ fprintf(stderr, "%s:insert_symmetric_tag()\n", PACKAGE);
if (!(change.start - change.end)) {
_DEBUG_ fprintf(stderr, "%s:insert_symmetric_tag():2\n", PACKAGE);
together = g_string_new("<");
together = g_string_append(together, tag);
together = g_string_append(together, ">");
together = g_string_append(together, tag);
together = g_string_append(together, ">");
insert_text(together->str, together->len);
g_string_free(together, TRUE);
move_cursor(strlen(tag) + 3, LEFT);
} else
insert_text_around(change, tag, strlen(tag));
_DEBUG_ fprintf(stderr, "%s:insert_symmetric_tag():3\n", PACKAGE);
gtk_window_set_focus(GTK_WINDOW(main_window), document->text_view);
}
void body_img_function(GtkWidget * window)
{
GtkWidget *filew;
gtk_grab_remove(body_elements.dialog);
filew = gtk_file_selection_new("Image File selection");
gtk_signal_connect(GTK_OBJECT(filew), "destroy", (GtkSignalFunc) destroy_message, &filew);
gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filew)->ok_button), "clicked",
(GtkSignalFunc) body_img_file_ok_sel, filew);
gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(filew)->cancel_button),
"clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT(filew));
gtk_widget_show(filew);
}
void body_img_file_ok_sel(GtkWidget * widget, GtkWidget * fs)
{
gtk_entry_set_text(GTK_ENTRY(body_elements.background.entry),
g_basename(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs))));
gtk_widget_destroy(GTK_WIDGET(fs));
gtk_grab_add(body_elements.dialog);
}
void href_function_ok(GtkWidget * widget, gpointer data)
{
GString *new_string;
clean_selected();
new_string = g_string_new("entry))))
new_string =
g_string_append(new_string,
gtk_entry_get_text(GTK_ENTRY
(GTK_COMBO(hyperlink.protocol.combo)->
entry)));
new_string =
g_string_append(new_string, gtk_entry_get_text(GTK_ENTRY(hyperlink.link.entry)));
new_string = g_string_append(new_string, "\">");
new_string =
g_string_append(new_string, gtk_entry_get_text(GTK_ENTRY(hyperlink.name.entry)));
new_string = g_string_append(new_string, ""); /* new string */
insert_text(new_string->str, new_string->len);
move_cursor(new_string->len - 4, RIGHT);
g_string_free(new_string, TRUE);
close_body_dialog(NULL, GTK_WIDGET(data));
focus_text_view();
}
GtkWidget *combo_in_frame(gchar * title, struct frame_combo *frame_combo, GList * list_items)
{
GtkWidget *combo_box;
frame_combo->frame = gtk_frame_new(title);
combo_box = gtk_hbox_new(TRUE, TRUE);
gtk_container_add(GTK_CONTAINER(frame_combo->frame), combo_box);
frame_combo->combo = gtk_combo_new();
gtk_combo_set_popdown_strings(GTK_COMBO(frame_combo->combo), list_items);
frame_combo->entry = (GTK_COMBO(frame_combo->combo)->entry);
gtk_entry_set_editable(GTK_ENTRY(frame_combo->entry), FALSE);
gtk_widget_show(frame_combo->combo);
gtk_box_pack_start(GTK_BOX(combo_box), frame_combo->combo, FALSE, FALSE, 30);
gtk_widget_show(combo_box);
gtk_widget_show(frame_combo->frame);
return combo_box;
}
void font_function_ok(GtkWidget * widget, gpointer data)
{
gchar *title1 = "";
GString *font_;
GString *font_option;
font_option = g_string_new("");
/* Now testing font color */
make_body_options_string(font_option, " color=\"", &font_options.color);
/* Now testing font face */
make_body_options_string(font_option, " face=\"", &font_options.face);
if (gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(font_options.size))) {
font_option = g_string_append(font_option, " size=\"");
font_option =
g_string_append_c(font_option,
gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON
(font_options.size)) + 48);
font_option = g_string_append(font_option, "\"");
}
font_ = g_string_new(title1);
font_ = g_string_append(font_, font_option->str);
font_ = g_string_append(font_, ">");
if (data)
font_ = g_string_append(font_, (gchar *) data);;
font_ = g_string_append(font_, title2);
/* String made... Now inserting */
_DEBUG_ fprintf(stderr, "%s:%s\n", PACKAGE, font_->str);
insert_text(font_->str, font_->len);
move_cursor(font_->len - 7, RIGHT);
if (data) {
g_free(data);
}
/*Freeing memory */
g_string_free(font_, TRUE);
g_string_free(font_option, TRUE);
close_body_dialog(NULL, GTK_WIDGET(font_options.dialog));
focus_text_view();
}
/**
* void switch_page
* - this is the callback when the event switch_page occurs
* - notebook_label, text, title are set according to the
* values retrieved from the GList ...
* - new text is focused, if not a gtkhtml widget
*/
void switch_page(GtkWidget * widget, GtkNotebookPage * page, gint page_num, gpointer user_data)
{
struct document *document;
gpointer blub;
int i = 0;
GtkTextBuffer *buffer;
GtkWidget *disable = NULL;
_DEBUG_ fprintf(stderr, "%s:page_num: %d\n", PACKAGE, page_num);
if (!nr_of_documents)
page_num = 0;
_DEBUG_ fprintf(stderr, "%s:length of list: %d\n", PACKAGE, g_list_length(documents));
_DEBUG_ fprintf(stderr, "%s:page_num: %d\n", PACKAGE, page_num);
document = (g_list_nth(documents, page_num))->data;
//strcpy(file, document->filename->str);
set_title_name_switch_page(page_num);
_DEBUG_ fprintf(stderr, "%s:document_rendered %d\n", PACKAGE, document->is_rendered);
if (!document->is_rendered) {
gtk_window_set_focus(GTK_WINDOW(main_window), document->text_view);
if (document->syntax_highlighting)
add_to_statusbar(gtk_source_language_get_name(document->language), TRUE);
else
add_to_statusbar(NULL, TRUE);
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(document->text_view));
g_object_set(G_OBJECT(buffer), "highlight", document->syntax_highlighting, NULL);
if (document->syntax_highlighting_menuitem) {
while ((blub = g_slist_nth_data(highlighting_group, i++))) {
GTK_CHECK_MENU_ITEM(blub)->active = FALSE;
}
GTK_CHECK_MENU_ITEM(document->syntax_highlighting_menuitem)->active = TRUE;
} else {
while ((blub = g_slist_nth_data(highlighting_group, i++))) {
GTK_CHECK_MENU_ITEM(blub)->active = FALSE;
}
blub = g_slist_nth_data(highlighting_group, i - 2);
GTK_CHECK_MENU_ITEM(blub)->active = TRUE;
}
update_statistic(buffer);
} else {
while ((blub = g_slist_nth_data(highlighting_group, i++))) {
GTK_CHECK_MENU_ITEM(blub)->active = FALSE;
}
add_to_statusbar(document->filename->str, TRUE);
}
disable =
gtk_item_factory_get_widget(GTK_ITEM_FACTORY(main_factory),
"/Options/Syntax Highlighting/Disable");
g_return_if_fail(GTK_IS_CHECK_MENU_ITEM(disable));
GTK_CHECK_MENU_ITEM(disable)->active = !document->syntax_highlighting;
}
void close_current_file()
{
gint page = -1;
close_file(NULL, &page);
}
/**
* void close_file
* - checking if current document has changed
* if yes, then ask user if would like to save file
*/
gboolean close_file(GtkWidget * widget, gpointer data)
{
GtkWidget *dialog;
gboolean modified = TRUE;
gint *page = (gint *) data;
struct document *document;
close_notebook = *page;
if (widget)
widget = widget;
if (nr_of_documents == -1)
return FALSE;
if (*page == -1)
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
else
document = (g_list_nth(documents, *page))->data;
if (document->is_rendered)
modified = FALSE;
else {
modified =
gtk_text_buffer_get_modified(gtk_text_view_get_buffer(GTK_TEXT_VIEW(document->
text_view)));
}
if (modified) {
_DEBUG_ fprintf(stderr, "%s:text has been changed after save event\n", PACKAGE);
dialog = gtk_message_dialog_new(GTK_WINDOW(main_window),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
"File is not saved.\nSave it now?");
gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_NO, GTK_RESPONSE_NO);
gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
case GTK_RESPONSE_OK:
close_ask_yes(document);
//never reached???
_DEBUG_ fprintf(stderr, "%s:never reached???\n", PACKAGE);
break;
case GTK_RESPONSE_NO:
close_ask_no();
break;
default:
break;
}
gtk_widget_destroy(GTK_WIDGET(dialog));
close_notebook = -1;
return TRUE;
}
really_close_file();
close_notebook = -1;
return FALSE;
}
/**
* void switch_html_page
* - sets the focus on the text widget
*/
void switch_html_page()
{
focus_text_view();
}
/**
* void really_close_file
* - current page of the notebook is removed
* and gint nr_of_notebook_child in the GList *documents
* gets new values...
* - the removed struct document *document is freed
* - the new value for gint nr_of_documents is assigned
* - GtkWidget *text is NULL if no more documents are opened
*/
void really_close_file()
{
gint page_num = close_notebook;
struct document *document;
if (close_notebook == -1)
page_num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main));
document = (g_list_nth(documents, page_num))->data;
if (!nr_of_documents) {
if (document->is_rendered) {
_DEBUG_ fprintf(stderr, "%s:document->is_rendered\n", PACKAGE);
documents = g_list_remove(documents, document);
g_free(document);
nr_of_documents--;
gtk_notebook_remove_page(GTK_NOTEBOOK(notebook_main), page_num);
add_to_statusbar(NULL, FALSE);
gtk_window_set_title(GTK_WINDOW(main_window), PACKAGE);
return;
} else {
GSList *languages = NULL;
gpointer blub;
int i = 0;
clean_buffer();
document->filename = g_string_new("Untitled");
document->new_document = TRUE;
gtk_text_buffer_set_modified(get_text_buffer(), FALSE);
set_title_name();
gtk_label_set_text(GTK_LABEL(document->notebook_label), "Untitled");
//reset highlighting to default
document->manager =
g_object_get_data(G_OBJECT(get_text_buffer()), "languages-manager");
languages = (GSList *)
gtk_source_languages_manager_get_available_languages(document->manager);
while ((blub = g_slist_nth_data(languages, i++))) {
if (globals.default_highlighting
&& !strcmp(globals.default_highlighting,
gtk_source_language_get_name(blub)))
document->language = blub;
}
g_object_set(G_OBJECT(get_text_buffer()), "highlight", TRUE, NULL);
g_object_get(G_OBJECT(get_text_buffer()), "highlight",
&(document->syntax_highlighting), NULL);
gtk_source_buffer_set_language(GTK_SOURCE_BUFFER(get_text_buffer()),
document->language);
if (document->syntax_highlighting)
add_to_statusbar(gtk_source_language_get_name(document->language),
TRUE);
else
add_to_statusbar(NULL, TRUE);
}
}
if (!nr_of_documents)
return;
documents = g_list_remove(documents, document);
g_free(document);
nr_of_documents--;
gtk_notebook_remove_page(GTK_NOTEBOOK(notebook_main), page_num);
for (page_num = 0; page_num <= nr_of_documents; page_num++) {
document = (g_list_nth(documents, page_num))->data;
document->nr_of_notebook_child = page_num;
}
if (nr_of_documents == -1) {
gtk_widget_hide(GTK_WIDGET(notebook_html));
}
}
void close_ask_no()
{
really_close_file();
}
void close_ask_yes(struct document *document)
{
document->close_file = TRUE;
save_file(NULL, document);
}
void load_done(GtkWidget * html, gpointer data)
{
struct document *document = (struct document *) data;
_DEBUG_ fprintf(stderr, "%s:title_changed %s\n", PACKAGE,
gtk_html_get_title(GTK_HTML(html)));
if (gtk_html_get_title(GTK_HTML(html)) && strlen(gtk_html_get_title(GTK_HTML(html))) > 0)
gtk_label_set_text(GTK_LABEL(((struct document *) (data))->notebook_label),
gtk_html_get_title(GTK_HTML(html)));
else
gtk_label_set_text(GTK_LABEL(((struct document *) (data))->notebook_label),
"Untitled");
((struct document *) (data))->filename = g_string_new(gtk_html_get_title(GTK_HTML(html)));
set_title_name_switch_page(document->nr_of_notebook_child);
}
/* parts copied from the gtkhtml3 test program */
GString *encode_buffer_to_html()
{
GtkTextBuffer *buffer;
GtkTextIter start, end;
gchar *erwin = NULL;
GString *str = g_string_new(NULL);
buffer = get_text_buffer();
gtk_text_buffer_get_start_iter(buffer, &start);
gtk_text_buffer_get_end_iter(buffer, &end);
erwin = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
_DEBUG_ fprintf(stderr, "%s:%s\n", PACKAGE, erwin);
if (strlen(erwin) <= 0) {
g_free(erwin);
return str;
}
do {
gunichar uc;
uc = g_utf8_get_char(erwin);
if (uc > 160)
g_string_append_printf(str, "%u;", uc);
else
g_string_append_c(str, uc);
} while ((erwin = g_utf8_next_char(erwin)) && *erwin);
return str;
}
void on_url(GtkHTML * html, const gchar * url, gpointer data)
{
if (url)
add_to_statusbar((gchar *) url, FALSE);
else
add_to_statusbar((gchar *) gtk_html_get_title(GTK_HTML(html)), TRUE);
}
void view_html()
{
struct document *document;
GtkWidget *image;
GtkWidget *button;
GtkWidget *label_box;
GString *html;
if (gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main)) == -1)
return;
document =
(g_list_nth(documents,
gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data;
if (document->is_rendered)
return;
if (nr_of_documents == -1)
gtk_widget_show(GTK_WIDGET(notebook_html));
document = g_malloc(sizeof(struct document));
memset(document, 0, sizeof(struct document));
document->text_view = gtk_html_new();
_DEBUG_ fprintf(stderr, "%s:new 1 text_view : %p\n", PACKAGE, document->text_view);
/* setting a default name for the notebook
this is probably unnecessary as it will be overwritten in
the load_done callback... just to be on the save side */
document->notebook_label = gtk_label_new("Untitled");
document->filename = g_string_new("Untitled");
document->is_rendered = TRUE;
document->nr_of_notebook_child = ++nr_of_documents;
documents = g_list_append(documents, document);
g_signal_connect(G_OBJECT(document->text_view), "load_done", G_CALLBACK(load_done),
document);
g_signal_connect(G_OBJECT(document->text_view), "on_url", G_CALLBACK(on_url),
(gpointer) document);
html = encode_buffer_to_html();
/* html is GString containing the text from our buffer */
if (html->len <= 0) {
documents = g_list_remove(documents, document);
nr_of_documents--;
g_free(document);
g_string_free(html, TRUE);
return;
}
/* this actually renders our html file */
gtk_html_load_from_string(GTK_HTML(document->text_view), html->str, -1);
/* free the GString */
g_string_free(html, TRUE);
gtk_widget_show(document->notebook_label);
put_in_scrollbar(document);
/* this is all for the button on the notebook label */
label_box = gtk_hbox_new(FALSE, FALSE);
gtk_box_pack_start(GTK_BOX(label_box), document->notebook_label, TRUE, TRUE, 0);
button = gtk_button_new();
image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
gtk_container_add(GTK_CONTAINER(button), image);
gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
gtk_widget_show(image);
gtk_widget_show(button);
gtk_box_pack_start(GTK_BOX(label_box), button, TRUE, TRUE, 0);
gtk_widget_show(label_box);
document->notebook = notebook_main;
document->changed = TRUE;
document->saved = TRUE;
document->close_file = FALSE;
gtk_notebook_append_page(GTK_NOTEBOOK(notebook_main), document->notebook_child, label_box);
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(close_file),
&document->nr_of_notebook_child);
gtk_notebook_set_page(GTK_NOTEBOOK(notebook_main), document->nr_of_notebook_child);
add_to_statusbar(NULL, TRUE);
}
void put_in_scrollbar(struct document *document)
{
GtkWidget *scrollbar;
document->notebook_child = gtk_hbox_new(FALSE, FALSE);
scrollbar = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbar), GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(scrollbar), document->text_view);
gtk_box_pack_start(GTK_BOX(document->notebook_child), scrollbar, TRUE, TRUE, 0);
gtk_widget_show(document->text_view);
gtk_widget_show(scrollbar);
gtk_widget_show(document->notebook_child);
}
/**
* displays the current message "*message" in the statusbar
* every displayed message will be prefixed with "erwin x.x - "
*
* @param message the message to display
* @param new if this is true "*message" is not appended to the current
* message but overiding the displayed message
*/
void add_to_statusbar(gchar * message, gboolean new)
{
gchar prefix[64];
static gchar *saved_message = NULL;
gchar *final_message = NULL;
gchar *status_message = NULL;
gint context_id = gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar), "Statusbar");
snprintf(prefix, 63, "%s %s - ", PACKAGE, VERSION);
if (!new && message) {
if (saved_message)
status_message =
(gchar *) malloc(strlen(saved_message) + strlen(message) + 4);
else
status_message = (gchar *) malloc(strlen(message) + 4);
status_message[0] = 0;
if (saved_message) {
strcat(status_message, saved_message);
strcat(status_message, " - ");
}
strcat(status_message, message);
} else if (message) {
if (saved_message)
free(saved_message);
status_message = strdup(message);
saved_message = strdup(message);
} else if (new && !message) {
if (saved_message)
free(saved_message);
saved_message = NULL;
}
final_message =
(gchar *) malloc(strlen(prefix) + ((status_message) ? strlen(status_message) : 0) + 3);
final_message[0] = 0;
strcat(final_message, prefix);
if (status_message)
strcat(final_message, status_message);
else
// -3 removes " - " which is unecessary if no text follows
final_message[strlen(final_message) - 3] = 0;
gtk_statusbar_push(GTK_STATUSBAR(status_bar), context_id, final_message);
free(final_message);
}
/**
* this functions does, by means of magic, close the first
* to this cursor position unclosed tag
*/
void close_tag()
{
GtkTextBuffer *buffer;
GtkTextIter insert, end_start, end_end, start_start, start_end;
gchar *result1 = NULL;
gchar *result2 = NULL;
gchar *temp = NULL;
gboolean search = FALSE;
GList *previous_tags = NULL;
guint length;
gint i;
gboolean continue_while;
buffer = get_text_buffer();
gtk_text_buffer_get_iter_at_mark(buffer, &insert, gtk_text_buffer_get_mark(buffer,
"insert"));
while (1) {
//search for ">"
search =
gtk_text_iter_backward_search(&insert, ">", GTK_TEXT_SEARCH_TEXT_ONLY,
&end_start, &end_end, NULL);
//no ">" found means no tag
if (!search)
break;
//if ">" found search for "<"
search = gtk_text_iter_backward_search(&end_start, "<", GTK_TEXT_SEARCH_TEXT_ONLY,
&start_start, &start_end, NULL);
//no "<" found means no tag
if (!search)
break;
//search between "<" and ">" for a ""
search = gtk_text_iter_backward_search(&end_end, "", GTK_TEXT_SEARCH_TEXT_ONLY,
&start_start, &start_end, &start_start);
//"" found means this was a closing tag
//we don't want to close a closing tag
//continue from here
insert = start_start;
if (search) {
result2 = gtk_text_buffer_get_text(buffer, &start_end, &end_start, TRUE);
previous_tags = g_list_append(previous_tags, result2);
continue;
}
result1 = gtk_text_buffer_get_text(buffer, &start_end, &end_start, TRUE);
temp = strchr(result1, 32);
if (temp)
*temp = 0;
//so this was an opening tag... but has there already
//been a closing tag for this tag
//we have to check all closing tags in the previous_tags list
length = g_list_length(previous_tags);
continue_while = FALSE;
for (i = 0; i < length; i++) {
temp = g_list_nth_data(previous_tags, i);
if (temp && !strcmp(result1, temp)) {
//we have found a opening tag
free(result1);
result1 = NULL;
continue_while = TRUE;
break;
}
}
if (continue_while)
continue;
break;
}
//free allocated memory
while (g_list_length(previous_tags) > 0) {
temp = (g_list_last(previous_tags))->data;
previous_tags = g_list_remove(previous_tags, temp);
if (temp)
free(temp);
}
if (result1) {
insert_text("", 2);
insert_text(result1, strlen(result1));
insert_text(">", 1);
free(result1);
}
}
/**
* from gnome-vfs-uri.c + changes
* to parse the result of a drop event
*
* @param uri_list a list files created by the drop event
* @return a GList where each element is the URI to a file
*/
GList *uri_list_parse(const gchar * uri_list)
{
/* Note that this is mostly very stolen from old libgnome/gnome-mime.c */
const gchar *p, *q;
gchar *retval;
gchar *uri;
GList *result = NULL;
g_return_val_if_fail(uri_list != NULL, NULL);
p = uri_list;
/* We don't actually try to validate the URI according to RFC
* 2396, or even check for allowed characters - we just ignore
* comments and trim whitespace off the ends. We also
* allow LF delimination as well as the specified CRLF.
*/
while (p != NULL) {
if (*p != '#') {
while (g_ascii_isspace(*p))
p++;
q = p;
while ((*q != '\0')
&& (*q != '\n')
&& (*q != '\r'))
q++;
if (q > p) {
q--;
while (q > p && g_ascii_isspace(*q))
q--;
retval = g_malloc(q - p + 2);
strncpy(retval, p, q - p + 1);
retval[q - p + 1] = '\0';
uri = strdup(retval);
g_free(retval);
if (uri != NULL)
result = g_list_prepend(result, uri);
}
}
p = strchr(p, '\n');
if (p != NULL)
p++;
}
return g_list_reverse(result);
}
/**
* callback for the drop event of a drag
* no idea what all the parameters mean
*/
GtkSignalFunc drop_file(GtkWidget * widget, GdkDragContext * context, gint x, gint y,
GtkSelectionData * selection_data, guint info, guint time,
gpointer user_data)
{
GList *list = NULL;
guint length;
int i;
list = uri_list_parse(selection_data->data);
length = g_list_length(list);
for (i = 0; i < length; i++) {
// +5 to start after "file:"
_open_file_ok(g_list_nth_data(list, i) + 5);
free(g_list_nth_data(list, i));
}
g_list_free(list);
return NULL;
}
/**
* makes the view sensitive to drop events
*
* @param view the GtkTextView to receive a drop event
*/
void make_dropable(GtkTextView * view)
{
static GtkTargetEntry drop_types[] = {
{"text/uri-list", 0, 0}
};
static gint n_drop_types = sizeof(drop_types) / sizeof(drop_types[0]);
GtkTargetList *tl;
tl = gtk_drag_dest_get_target_list(GTK_WIDGET(view));
gtk_target_list_add_table(tl, drop_types, n_drop_types);
g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(drop_file), view);
}
/**
* set the default font
*
* @param view the GtkTextView which wants the font changed
*/
void set_view_font(GtkTextView * view)
{
PangoFontDescription *font_desc;
font_desc = pango_font_description_from_string("Mono");
gtk_widget_modify_font(GTK_WIDGET(view), font_desc);
pango_font_description_free(font_desc);
}