diff --git a/glade/mainWindow.glade b/glade/mainWindow.glade index 925a569..7eb122e 100644 --- a/glade/mainWindow.glade +++ b/glade/mainWindow.glade @@ -1,5 +1,5 @@ - + @@ -479,6 +479,19 @@ 1 + + + New Entry + True + True + True + + + False + True + 1 + + @@ -512,20 +525,21 @@ vertical 4 - + True False - 4 + 4 + 4 True False + end Entry display mode: - False - True - 0 + 0 + 0 @@ -534,9 +548,76 @@ False - False - True - 1 + 1 + 0 + + + + + True + False + end + New entry date format: + + + 0 + 1 + + + + + True + False + + + True + False + + + True + False + + + page0 + page0 + + + + + True + True + + + page1 + page1 + 1 + + + + + False + True + 0 + + + + + ... + True + True + True + Use custom format + + + False + True + 1 + + + + + 1 + 1 diff --git a/src/mainwindow.c b/src/mainwindow.c index 13a0193..af0fae2 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -1,6 +1,15 @@ #include "mainwindow.h" #include "mdiary.h" +const gchar *default_template[] = {"# Title\n" + "Date: ", "\0", + "\n" + "Summary: \n" + "Tags: \n" + "\n" + "Text", + NULL}; + static gboolean mainWindow_workspace_entry_visible(GtkTreeModel *model, GtkTreeIter *iter, struct mainWindow *mainWindow) @@ -206,9 +215,9 @@ static void mainWindow_configure_workspaceTreeView(struct mainWindow *mainWindow G_TYPE_STRING); mainWindow->workspaceListFiltered = GTK_TREE_MODEL_FILTER( - gtk_tree_model_filter_new( - GTK_TREE_MODEL(mainWindow->workspaceListStore), - NULL)); + gtk_tree_model_filter_new( + GTK_TREE_MODEL(mainWindow->workspaceListStore), + NULL)); gtk_tree_model_filter_set_visible_func(mainWindow->workspaceListFiltered, (GtkTreeModelFilterVisibleFunc) mainWindow_workspace_entry_visible, @@ -408,6 +417,10 @@ static void mainWindow_connect_signals(struct mainWindow *mainWindow) "changed", (GCallback) mainWindow_workspace_search_changed, mainWindow); + g_signal_connect(mainWindow->buttonNew, + "clicked", + (GCallback) mainWindow_new_entry_clicked, + mainWindow); g_signal_connect(mainWindow->buttonDecrypt, "clicked", (GCallback) mainWindow_decrypt_gpg_clicked, @@ -490,6 +503,59 @@ static void mainWindow_settings_combo_changed(GtkComboBox *widget, gpointer user mainWindow_entrySelected(NULL, user_data); } +static void mainWindow_settings_comboNewDateFormat_changed(GtkComboBox *widget, gpointer user_data) +{ + struct mainWindow *mainWindow = (struct mainWindow *)user_data; + + mainWindow_set_new_file_date_format(mainWindow, gtk_combo_box_get_active_id(GTK_COMBO_BOX(mainWindow->settingsDialog.comboNewDateFormat))); +} + + +static void mainWindow_settings_buttonCustomNewFileDateFormat_clicked(GtkComboBox *widget, gpointer user_data) +{ + struct mainWindow *mainWindow = (struct mainWindow *)user_data; + + if (gtk_stack_get_visible_child(GTK_STACK(mainWindow->settingsDialog.stackNewDateFormat)) == mainWindow->settingsDialog.entryNewDateFormat) { + mainWindow_set_new_file_date_format(mainWindow, gtk_entry_get_text(mainWindow->settingsDialog.entryNewDateFormat)); + gtk_stack_set_visible_child(GTK_STACK(mainWindow->settingsDialog.stackNewDateFormat), + mainWindow->settingsDialog.comboNewDateFormat); + gtk_button_set_label(GTK_BUTTON(mainWindow->settingsDialog.buttonCustomNewFileDateFormat), "..."); + } else { + gtk_stack_set_visible_child(GTK_STACK(mainWindow->settingsDialog.stackNewDateFormat), + mainWindow->settingsDialog.entryNewDateFormat); + gtk_button_set_label(GTK_BUTTON(mainWindow->settingsDialog.buttonCustomNewFileDateFormat), "OK"); + } +} + +const gchar *newDateFormats[] = {"%d.%m.%Y %H:%M", + "%Y-%m-%d %H:%M", + NULL}; + +void mainWindow_set_new_file_date_format(struct mainWindow *mainWindow, gchar *fmt) +{ + GDateTime *datetime; + gchar *text; + + if (!fmt) { + fmt = newDateFormats[0]; + } + g_free(mainWindow->newFileDateFormat); + mainWindow->newFileDateFormat = g_strdup(fmt); + + gtk_entry_set_text(mainWindow->settingsDialog.entryNewDateFormat, fmt); + + /* Custom format -> Add to list for this session */ + if (!gtk_combo_box_set_active_id(mainWindow->settingsDialog.comboNewDateFormat, fmt)) { + datetime = g_date_time_new_now_local(); + text = g_date_time_format(datetime, fmt); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(mainWindow->settingsDialog.comboNewDateFormat), + fmt, text); + g_free(text); + g_date_time_unref(datetime); + gtk_combo_box_set_active_id(mainWindow->settingsDialog.comboNewDateFormat, fmt); + } +} + static gboolean mainWindow_settings_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) { gtk_widget_hide(widget); @@ -503,6 +569,10 @@ void mainWindow_settings_show(struct mainWindow *mainWindow) static void mainWindow_configure_settings_dialog(struct mainWindow *mainWindow) { + GDateTime *datetime; + int i; + gchar *text; + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(mainWindow->settingsDialog.comboDisplayMode), "text", "Text only"); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(mainWindow->settingsDialog.comboDisplayMode), @@ -510,11 +580,31 @@ static void mainWindow_configure_settings_dialog(struct mainWindow *mainWindow) gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(mainWindow->settingsDialog.comboDisplayMode), "html", "Full HTML with images"); + datetime = g_date_time_new_now_local(); + for (i= 0; newDateFormats[i]; ++i) { + text = g_date_time_format(datetime, newDateFormats[i]); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(mainWindow->settingsDialog.comboNewDateFormat), + newDateFormats[i], text); + g_free(text); + } + g_date_time_unref(datetime); + + g_signal_connect(mainWindow->settingsDialog.comboDisplayMode, "changed", (GCallback) mainWindow_settings_combo_changed, mainWindow); + g_signal_connect(mainWindow->settingsDialog.comboNewDateFormat, + "changed", + (GCallback) mainWindow_settings_comboNewDateFormat_changed, + mainWindow); + + g_signal_connect(mainWindow->settingsDialog.buttonCustomNewFileDateFormat, + "clicked", + (GCallback) mainWindow_settings_buttonCustomNewFileDateFormat_clicked, + mainWindow); + g_signal_connect(mainWindow->settingsDialog.settingsDialog, "delete-event", (GCallback) mainWindow_settings_delete_event, @@ -551,6 +641,7 @@ struct mainWindow *mainWindow_new() mainWindow->buttonClearSearch = GTK_WIDGET(gtk_builder_get_object(builder, "buttonClearSearch")); mainWindow->headerBar = GTK_WIDGET(gtk_builder_get_object(builder, "headerBar")); mainWindow->labelDateToDate = GTK_WIDGET(gtk_builder_get_object(builder, "label_date_to_date")); + mainWindow->buttonNew = GTK_WIDGET(gtk_builder_get_object(builder, "buttonNew")); mainWindow->buttonDecrypt = GTK_WIDGET(gtk_builder_get_object(builder, "buttonDecrypt")); mainWindow->stackRenderMode = GTK_WIDGET(gtk_builder_get_object(builder, "stackRenderMode")); mainWindow->entryListView = GTK_TREE_VIEW(gtk_builder_get_object(builder, "entryListView")); @@ -565,8 +656,14 @@ struct mainWindow *mainWindow_new() mainWindow->workspaceListSelection = GTK_TREE_SELECTION(gtk_builder_get_object(builder, "treeWorkspaceSelection")); - mainWindow->settingsDialog.settingsDialog = GTK_WIDGET(gtk_builder_get_object(builder, "settingsDialog")); - mainWindow->settingsDialog.comboDisplayMode = GTK_WIDGET(gtk_builder_get_object(builder, "comboDisplayMode")); + mainWindow->currentWorkspaceUrl = NULL; + + mainWindow->settingsDialog.settingsDialog = GTK_WIDGET(gtk_builder_get_object(builder, "settingsDialog")); + mainWindow->settingsDialog.comboDisplayMode = GTK_WIDGET(gtk_builder_get_object(builder, "comboDisplayMode")); + mainWindow->settingsDialog.comboNewDateFormat = GTK_WIDGET(gtk_builder_get_object(builder, "comboNewDateFormat")); + mainWindow->settingsDialog.stackNewDateFormat = GTK_WIDGET(gtk_builder_get_object(builder, "stackNewDateFormat")); + mainWindow->settingsDialog.entryNewDateFormat = GTK_WIDGET(gtk_builder_get_object(builder, "entryNewDateFormat")); + mainWindow->settingsDialog.buttonCustomNewFileDateFormat = GTK_WIDGET(gtk_builder_get_object(builder, "buttonCustomNewFileDateFormat")); mainWindow->filterSettings.time_start = 0; mainWindow->filterSettings.time_end = -1; @@ -576,6 +673,8 @@ struct mainWindow *mainWindow_new() mainWindow->renderer = RENDERER_NONE; + mainWindow->newFileDateFormat = NULL; + gtk_builder_connect_signals(builder, NULL); g_object_unref(G_OBJECT(builder)); @@ -591,6 +690,7 @@ struct mainWindow *mainWindow_new() mainWindow_configure_entry_completion(mainWindow); mainWindow_set_meta_information(mainWindow, 0, 0, TRUE); + mainWindow_set_new_file_date_format(mainWindow, NULL); mainWindow_renderer_set(mainWindow, RENDERER_TEXT); return mainWindow; @@ -704,9 +804,9 @@ static void mainWindow_set_text(struct mainWindow *mainWindow, gchar *text, gcha base_url = g_strdup_printf("file://%s", file_url); file = g_file_new_for_path(tempfile_path); stream = g_file_replace( - file, NULL, FALSE, - G_FILE_CREATE_NONE, - NULL, NULL); + file, NULL, FALSE, + G_FILE_CREATE_NONE, + NULL, NULL); g_output_stream_write(G_OUTPUT_STREAM(stream), text, strlen(text), NULL, NULL); g_output_stream_flush(G_OUTPUT_STREAM(stream), NULL, NULL); @@ -779,6 +879,27 @@ void mainWindow_entrySelected(GtkWidget *widget, gpointer user_data) } } +/** + * @brief mainWindow_openExternalEditor opens the supplied path with the default system editor + * @param mainWindow + * @param path is the file to open + */ +void mainWindow_openExternalEditor(gchar *path) +{ + GFile *file; + GAppInfo *info; + GList *files = NULL; + + g_info("Opening entry in external editor."); + file = g_file_new_for_path(path); + info = g_file_query_default_handler(file, NULL, NULL); + files = g_list_append(files, (gpointer) file); + g_app_info_launch(info, files, NULL, NULL); + g_list_free(files); // Content is freed individually + g_object_unref(info); + g_object_unref(file); +} + /** * @brief mainWindow_entryActivated is the callback when the user doubleclicks or presses enter on an entry * @param widget is the entryListView @@ -786,9 +907,7 @@ void mainWindow_entrySelected(GtkWidget *widget, gpointer user_data) */ void mainWindow_entryActivated(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data) { - GFile *file; - GAppInfo *info; - GList *files = NULL; + GtkTreeModel *model; GtkTreeIter iter; GtkTreeView *treeview = (GtkTreeView*) widget; @@ -797,16 +916,9 @@ void mainWindow_entryActivated(GtkWidget *widget, GtkTreePath *path, GtkTreeView model = gtk_tree_view_get_model(treeview); if (gtk_tree_model_get_iter(model, &iter, path)) { - g_info("Opening entry in external editor."); gtk_tree_model_get(model, &iter, COL_URL, &name, -1); - file = g_file_new_for_path(name); - info = g_file_query_default_handler(file, NULL, NULL); - files = g_list_append(files, (gpointer) file); - g_app_info_launch(info, files, NULL, NULL); + mainWindow_openExternalEditor(name); g_free(name); - g_list_free(files); // Content is freed individually - g_object_unref(info); - g_object_unref(file); } } @@ -844,13 +956,13 @@ void mainWindow_filterChanged(GtkWidget *widget, gpointer user_data) } mainWindow->filterSettings.search_title = gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(mainWindow->checkSearchTitle)); + GTK_TOGGLE_BUTTON(mainWindow->checkSearchTitle)); mainWindow->filterSettings.search_tags = gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(mainWindow->checkSearchTags)); + GTK_TOGGLE_BUTTON(mainWindow->checkSearchTags)); mainWindow->filterSettings.search_text = gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(mainWindow->checkSearchText)); + GTK_TOGGLE_BUTTON(mainWindow->checkSearchText)); mainWindow->filterSettings.search_summary = gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(mainWindow->checkSearchSummary)); + GTK_TOGGLE_BUTTON(mainWindow->checkSearchSummary)); gtk_tree_model_filter_refilter(mainWindow->entryListFiltered); } @@ -949,6 +1061,10 @@ void mainWindow_switch_workspace(struct mainWindow *mainWindow, gchar *path, gbo mdiary_reset_store(mainWindow->entryListStore, mainWindow->completionListStore); mdiary_scanner = mdiary_scanner_new(gpg_enabled); + + g_free(mainWindow->currentWorkspaceUrl); + mainWindow->currentWorkspaceUrl = g_strdup(path); + if (mdiary_scan_to_store(mdiary_scanner, path, mainWindow->entryListStore, mainWindow->completionListStore)) { mainWindow_set_meta_information(mainWindow, mdiary_scanner->time_earliest, mdiary_scanner->time_latest, @@ -1028,6 +1144,80 @@ void mainWindow_otherWorkspaceClicked(GtkWidget *widget, gpointer user_data) gtk_widget_destroy(dialog); } +/** + * @brief mainWindow_otherWorkspaceClicked is called when the user clicks the New Entry button. + * @param widget N/A + * @param user_data struct mainWindow * + */ +void mainWindow_new_entry_clicked(GtkWidget *widget, gpointer user_data) +{ + void close_dialog(GtkWidget *widget, gpointer dlg) + { + gtk_dialog_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK); + } + + struct mainWindow *mainWindow = (struct mainWindow *)user_data; + GtkWidget *dialog; + GtkWidget *textInput; + gchar *path; + FILE *fd; + gchar *default_path; + GDateTime *datetime; + int i; + + dialog = gtk_message_dialog_new(GTK_WINDOW(mainWindow->mainWindow), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, + "Please enter the filename of the entry"); + textInput = gtk_entry_new(); + datetime = g_date_time_new_now_local(); + default_path = g_date_time_format(datetime, "%Y/%Y-%m-%d"); + gtk_entry_set_text(GTK_ENTRY(textInput), default_path); + g_free(default_path); + gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), textInput, true, true, 4); + g_signal_connect(textInput, + "activate", + (GCallback) close_dialog, + dialog); + gtk_widget_show(textInput); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) { + path = (gchar*) gtk_entry_get_text(GTK_ENTRY(textInput)); + if (strlen(path) > 0) { + if (path[0] != '/') + path = g_strdup_printf("%s/%s.md", mainWindow->currentWorkspaceUrl, path); + else + path = g_strdup_printf("%s.md", path); + fd = fopen(path, "r"); + if (fd) { + fclose(fd); + g_warning("File '%s' already exists.", path); + } else { + fd = fopen(path, "w"); + if (fd) { + for (i = 0; default_template[i] != NULL; ++i) { + if (default_template[i][0] == '\0') { + default_path = g_date_time_format(datetime, mainWindow->newFileDateFormat); + fwrite(default_path, sizeof(char), strlen(default_path), fd); + g_free(default_path); + } else { + fwrite(default_template[i], sizeof(char), strlen(default_template[i]), fd); + } + } + fclose(fd); + mainWindow_openExternalEditor(path); + } else { + g_warning("Could not open file '%s' for writing.", path); + } + } + } + } + + g_date_time_unref(datetime); + + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + void mainWindow_decrypt_gpg_clicked(GtkWidget *widget, gpointer user_data) { struct mainWindow *mainWindow = (struct mainWindow *)user_data; diff --git a/src/mainwindow.h b/src/mainwindow.h index 7337531..3348c85 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -42,6 +42,7 @@ struct mainWindow { GtkWidget *buttonClearSearch; GtkWidget *headerBar; GtkWidget *labelDateToDate; + GtkWidget *buttonNew; GtkWidget *buttonDecrypt; GtkWidget *webkitView; GtkWidget *webkitScrollArea; @@ -51,6 +52,8 @@ struct mainWindow { GtkTextBuffer *textBuffer; GtkEntryCompletion *searchEntryCompletion; + gchar *currentWorkspaceUrl; + GtkListStore *completionListStore; GtkListStore *entryListStore; GtkWidget *selectedDateEntry; @@ -79,9 +82,15 @@ struct mainWindow { GtkListStore *workspaceListStore; GtkTreeModelFilter *workspaceListFiltered; + gchar *newFileDateFormat; + struct settingsDialog { GtkWidget *settingsDialog; GtkWidget *comboDisplayMode; + GtkWidget *stackNewDateFormat; + GtkWidget *comboNewDateFormat; + GtkWidget *buttonCustomNewFileDateFormat; + GtkWidget *entryNewDateFormat; } settingsDialog; }; @@ -99,6 +108,7 @@ void mainWindow_workspaceListClicked(GtkWidget *widget, void mainWindow_clearSearch(GtkWidget *widget, gpointer user_data); void mainWindow_calendarSelected(GtkWidget *widget, gpointer user_data); void mainWindow_entrySelected(GtkWidget *widget, gpointer user_data); +void mainWindow_openExternalEditor(gchar *path); void mainWindow_entryActivated(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data); void mainWindow_filterChanged(GtkWidget *widget, gpointer user_data); void mainWindow_workspace_search_changed(GtkWidget *widget, gpointer user_data); @@ -106,9 +116,11 @@ void mainWindow_checkDate(GtkWidget *widget, gint event, gpointer user_data); void mainWindow_dateIconPress(GtkWidget *widget, gint icon_pos, gint event, gpointer user_data); void mainWindow_add_recent_workspace(struct mainWindow *mainWindow, gchar *path, gboolean append); void mainWindow_switch_workspace(struct mainWindow *mainWindow, gchar *path, gboolean gpg_enabled); +void mainWindow_new_entry_clicked(GtkWidget *widget, gpointer user_data); void mainWindow_decrypt_gpg_clicked(GtkWidget *widget, gpointer user_data); void mainWindow_renderer_set(struct mainWindow *mainWindow, enum renderer_mode state); void mainWindow_settings_show(struct mainWindow *mainWindow); gboolean mainWindow_toggleSummaryWrap(GtkWidget *widget, GdkEvent *event, gpointer user_data); +void mainWindow_set_new_file_date_format(struct mainWindow *mainWindow, gchar *fmt); #endif /* MAINWINDOW_H */ diff --git a/src/settings.c b/src/settings.c index e7e8a66..edc2e70 100644 --- a/src/settings.c +++ b/src/settings.c @@ -20,6 +20,14 @@ static void mdiary_settings_parse_line(gchar *line, struct mdiary_settings *sett mainWindow_renderer_set(settings->mainWindow, atoi(g_match_info_fetch(match_info, 1))); } g_regex_unref(regex); + + regex = g_regex_new("^newfileformat = (.*)", G_REGEX_RAW, 0, NULL); + if (g_regex_match(regex, line, 0, &match_info) && + g_regex_get_capture_count(regex) > 0 && + g_match_info_matches(match_info)) { + mainWindow_set_new_file_date_format(settings->mainWindow, g_match_info_fetch(match_info, 1)); + } + g_regex_unref(regex); } gboolean mdiary_load_settings(gchar *filename, struct mdiary_settings *settings) @@ -70,9 +78,9 @@ gboolean mdiary_save_settings(gchar *filename, struct mdiary_settings *settings) file = g_file_new_for_path(filename); stream = g_file_replace( - file, NULL, FALSE, - G_FILE_CREATE_NONE, - NULL, NULL); + file, NULL, FALSE, + G_FILE_CREATE_NONE, + NULL, NULL); output_buffer = g_strdup_printf("renderer = %d\n", settings->mainWindow->renderer); @@ -80,6 +88,11 @@ gboolean mdiary_save_settings(gchar *filename, struct mdiary_settings *settings) output_buffer, strlen(output_buffer), NULL, NULL); g_free(output_buffer); + output_buffer = g_strdup_printf("newfileformat = %s\n", settings->mainWindow->newFileDateFormat); + g_output_stream_write(G_OUTPUT_STREAM(stream), + output_buffer, strlen(output_buffer), NULL, NULL); + g_free(output_buffer); + if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(settings->mainWindow->workspaceListStore), &iter)) { do { gtk_tree_model_get(GTK_TREE_MODEL(settings->mainWindow->workspaceListStore), &iter,