/* iridium-window.c * * Copyright 2018 Matthias Vogelgesang * * 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 3 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, see . */ #include #include #include "iridium-config.h" #include "iridium-markdown.h" #include "iridium-note.h" #include "iridium-note-row.h" #include "iridium-standard-file.h" #include "iridium-tag-row.h" #include "iridium-window.h" struct _IridiumWindow { GtkApplicationWindow parent_instance; GtkHeaderBar *header_bar; GtkListBox *tag_list; GtkListBox *note_list; GtkWidget *title_entry; GtkWidget *source_view; GtkWidget *main_pane; GtkSearchBar *search_bar; GtkSearchEntry *search_entry; GtkToggleButton *toggle_html_view; GtkRevealer *notification_revealer; WebKitWebView *html_view; GBinding *title_binding; GBinding *content_binding; IridiumMarkdown *markdown; IridiumStandardFile *client; }; G_DEFINE_TYPE (IridiumWindow, iridium_window, GTK_TYPE_APPLICATION_WINDOW) static void on_tag_selected (IridiumWindow *self, IridiumTagRow *row, gpointer user_data) { gtk_list_box_invalidate_filter (self->note_list); } static void on_search_changed (IridiumWindow *self, GtkSearchEntry *entry) { gtk_list_box_invalidate_filter (self->note_list); } static void on_markdown_compiled (GObject *object, GAsyncResult *result, gpointer user_data) { IridiumWindow *window; gchar *html; GError *error = NULL; window = IRIDIUM_WINDOW (user_data); html = iridium_markdown_compile_finish (object, result, &error); webkit_web_view_load_html (window->html_view, html, NULL); g_free (html); } static void on_note_selected (IridiumWindow *self, IridiumNoteRow *row, gpointer user_data) { IridiumNote *note; GtkTextBuffer *buffer; GBindingFlags flags; GtkTextIter start; GtkTextIter end; gchar *text; if (self->title_binding != NULL) g_clear_object (&self->title_binding); if (self->content_binding != NULL) g_clear_object (&self->content_binding); if (row == NULL) return; note = iridium_note_row_get_note (row); flags = G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE; buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view)); self->title_binding = g_object_bind_property (note, "title", self->title_entry, "text", flags); self->content_binding = g_object_bind_property (note, "content", buffer, "text", flags); gtk_text_buffer_get_start_iter (buffer, &start); gtk_text_buffer_get_end_iter (buffer, &end); text = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE); iridium_markdown_compile_async (self->markdown, text, G_PRIORITY_DEFAULT, NULL, on_markdown_compiled, self); g_free (text); } static void search_activated (GAction *action, GVariant *param, IridiumWindow *self) { gtk_search_bar_set_search_mode (self->search_bar, !gtk_search_bar_get_search_mode (self->search_bar)); } static gboolean note_visible (IridiumNoteRow *row, IridiumWindow *window) { IridiumNote *note; IridiumTagRow *tag_row; tag_row = IRIDIUM_TAG_ROW (gtk_list_box_get_selected_row (window->tag_list)); if (tag_row == NULL) return TRUE; note = iridium_note_row_get_note (row); if (!iridium_note_has_tag (note, iridium_tag_row_get_tag (tag_row))) { return FALSE; } if (gtk_search_bar_get_search_mode (window->search_bar) && gtk_entry_get_text_length (GTK_ENTRY (window->search_entry)) > 0) { return iridium_note_matches_fuzzy (note, gtk_entry_get_text (GTK_ENTRY (window->search_entry))); } return TRUE; } static gint note_date_cmp (IridiumNoteRow *row1, IridiumNoteRow *row2, gpointer user_data) { GDateTime *dt1; GDateTime *dt2; dt1 = iridium_note_get_last_modified (iridium_note_row_get_note (row1)); dt2 = iridium_note_get_last_modified (iridium_note_row_get_note (row2)); /* sort later before earlier notes */ return g_date_time_compare (dt2, dt1); } static void on_standard_file_connected (GObject *object, GAsyncResult *result, gpointer user_data) { IridiumWindow *self; GList *notes; IridiumTag *tag_all; self = IRIDIUM_WINDOW (user_data); tag_all = iridium_tag_new ("All"); /* TODO: implement iridium_standard_file_connect_finish */ notes = iridium_standard_file_load (self->client, "sn.json"); for (GList *it = g_list_first (notes); it != NULL; it = g_list_next (it)) { IridiumNote *note; note = IRIDIUM_NOTE (it->data); iridium_note_add_tag (note, tag_all); gtk_list_box_insert (self->note_list, iridium_note_row_new (note), -1); } gtk_list_box_insert (self->tag_list, iridium_tag_row_new (tag_all), -1); g_list_free (notes); gtk_widget_show_all (GTK_WIDGET (self->note_list)); gtk_widget_show_all (GTK_WIDGET (self->tag_list)); gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); } static void on_notification_close_clicked (IridiumWindow *self, GtkButton *button) { gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); } static void iridium_window_dispose (GObject *object) { IridiumWindow *self; self = IRIDIUM_WINDOW (object); g_clear_object (&self->title_binding); g_clear_object (&self->content_binding); g_clear_object (&self->markdown); g_clear_object (&self->client); G_OBJECT_CLASS (iridium_window_parent_class)->dispose (object); } static void iridium_window_class_init (IridiumWindowClass *klass) { GObjectClass *oclass; GtkWidgetClass *widget_class; oclass = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); oclass->dispose = iridium_window_dispose; gtk_widget_class_set_template_from_resource (widget_class, "/net/bloerg/Iridium/iridium-window.ui"); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, header_bar); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, tag_list); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, note_list); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, source_view); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, title_entry); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, main_pane); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, search_bar); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, search_entry); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, html_view); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, toggle_html_view); gtk_widget_class_bind_template_child (widget_class, IridiumWindow, notification_revealer); gtk_widget_class_bind_template_callback (widget_class, on_tag_selected); gtk_widget_class_bind_template_callback (widget_class, on_note_selected); gtk_widget_class_bind_template_callback (widget_class, on_search_changed); gtk_widget_class_bind_template_callback (widget_class, on_notification_close_clicked); } static void iridium_window_init (IridiumWindow *self) { GtkSourceLanguageManager *manager; GtkStyleProvider *provider; GtkSourceBuffer *buffer; GSimpleAction *action; const gchar *server; const gchar *email; gchar *password; GError *error = NULL; gtk_widget_init_template (GTK_WIDGET (self)); self->title_binding = NULL; self->content_binding = NULL; self->markdown = iridium_markdown_new (); action = g_simple_action_new ("search", NULL); g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (action)); g_signal_connect (action, "activate", G_CALLBACK (search_activated), self); g_object_unref (action); g_object_bind_property (self->toggle_html_view, "active", self->html_view, "visible", G_BINDING_DEFAULT); gtk_search_bar_connect_entry (self->search_bar, GTK_ENTRY (self->search_entry)); manager = gtk_source_language_manager_get_default (); buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view))); gtk_source_buffer_set_language (buffer, gtk_source_language_manager_get_language (manager, "markdown")); g_object_unref (manager); provider = GTK_STYLE_PROVIDER (gtk_css_provider_get_default ()); gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (provider), "/net/bloerg/Iridium/iridium.css"); gtk_style_context_add_provider_for_screen (gtk_window_get_screen (GTK_WINDOW (self)), provider, GTK_STYLE_PROVIDER_PRIORITY_USER); self->client = iridium_standard_file_new (); server = "https://sf.bloerg.net"; email = "matthias.vogelgesang@gmail.com"; /* TODO: add dialog */ password = secret_password_lookup_sync (STANDARD_FILE_SCHEMA, NULL, &error, "email", email, "server", server, NULL); gtk_revealer_set_reveal_child (self->notification_revealer, TRUE); iridium_standard_file_connect_async (self->client, server, email, password, NULL, on_standard_file_connected, self); secret_password_free (password); gtk_list_box_set_filter_func (self->note_list, (GtkListBoxFilterFunc) note_visible, self, NULL); gtk_list_box_set_sort_func (self->note_list, (GtkListBoxSortFunc) note_date_cmp, NULL, NULL); gtk_widget_show_all (GTK_WIDGET (self->tag_list)); gtk_widget_show_all (GTK_WIDGET (self->note_list)); }