diff options
author | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2015-05-25 10:09:06 -0300 |
---|---|---|
committer | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2015-05-25 10:09:06 -0300 |
commit | 401d0bf5081911bb89ef99d6e0fbeaf6d2a7a940 (patch) | |
tree | 5472a37459de1180cca00ac2f6f39d562ae19617 | |
parent | 56730c0e3379be47ef3916902b34fef736cd6464 (diff) | |
download | gnome-todo-wip/task-list.tar.gz |
try to update tasks et alwip/task-list
-rw-r--r-- | data/todo.gresource.xml | 1 | ||||
-rw-r--r-- | data/ui/edit-pane.ui | 303 | ||||
-rw-r--r-- | data/ui/list-view.ui | 194 | ||||
-rw-r--r-- | data/ui/source-selector.ui | 232 | ||||
-rw-r--r-- | data/ui/task-row.ui | 18 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/gtd-arrow-frame.c | 28 | ||||
-rw-r--r-- | src/gtd-edit-pane.c | 365 | ||||
-rw-r--r-- | src/gtd-edit-pane.h | 42 | ||||
-rw-r--r-- | src/gtd-list-view.c | 52 | ||||
-rw-r--r-- | src/gtd-list-view.h | 2 | ||||
-rw-r--r-- | src/gtd-task-row.c | 86 | ||||
-rw-r--r-- | src/gtd-task.c | 8 |
13 files changed, 1240 insertions, 95 deletions
diff --git a/data/todo.gresource.xml b/data/todo.gresource.xml index 4a9de563..c8cc0c57 100644 --- a/data/todo.gresource.xml +++ b/data/todo.gresource.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <gresources> <gresource prefix="/org/gnome/todo"> + <file compressed="true" preprocess="xml-stripblanks">ui/edit-pane.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/list-view.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/menus.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/task-list-item.ui</file> diff --git a/data/ui/edit-pane.ui b/data/ui/edit-pane.ui new file mode 100644 index 00000000..231c07fa --- /dev/null +++ b/data/ui/edit-pane.ui @@ -0,0 +1,303 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.18.1 --> +<interface> + <requires lib="gtk+" version="3.16"/> + <template class="GtdEditPane" parent="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="row_spacing">12</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkScrolledWindow" id="scrolled_window"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="hscrollbar_policy">never</property> + <child> + <object class="GtkViewport" id="viewport"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkGrid" id="main_grid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_top">6</property> + <property name="margin_bottom">12</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkButton" id="close_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="margin_right">12</property> + <property name="relief">none</property> + <signal name="clicked" handler="gtd_edit_pane__close_button_clicked" object="GtdEditPane" swapped="no"/> + <child> + <object class="GtkImage" id="close_button_image"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">window-close-symbolic</property> + </object> + </child> + <style> + <class name="image-button"/> + <class name="flat"/> + </style> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="details_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_left">12</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes"><b>Details</b></property> + <property name="use_markup">True</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkSeparator" id="separator"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkGrid" id="grid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="vexpand">True</property> + <property name="border_width">12</property> + <property name="row_spacing">12</property> + <child> + <object class="GtkLabel" id="notes_dim_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Notes</property> + <property name="xalign">0</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="notes_scrolled_window"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <property name="min_content_width">325</property> + <property name="min_content_height">225</property> + <child> + <object class="GtkViewport" id="notes_viewport"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkTextView" id="notes_textview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="accepts_tab">False</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="due_date_dim_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Due Date</property> + <property name="xalign">0</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkMenuButton" id="date_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="popover">date_popover</property> + <child> + <object class="GtkBox" id="date_button_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="date_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkImage" id="date_button_image"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">pan-down-symbolic</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">3</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="priority_dim_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Priority</property> + <property name="xalign">0</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">4</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="priority_combo"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="active">0</property> + <items> + <item translatable="yes">None</item> + <item translatable="yes">Low</item> + <item translatable="yes">Medium</item> + <item translatable="yes">High</item> + </items> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">5</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="remove_button"> + <property name="label" translatable="yes">Delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="valign">end</property> + <property name="vexpand">True</property> + <style> + <class name="destructive-action"/> + </style> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">6</property> + <property name="width">2</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + <property name="width">2</property> + </packing> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </template> + <object class="GtkPopover" id="date_popover"> + <property name="can_focus">False</property> + <property name="border_width">12</property> + <property name="position">bottom</property> + <child> + <object class="GtkBox" id="date_popover_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="GtkCalendar" id="calendar"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="show_week_numbers">True</property> + <signal name="day-selected" handler="gtd_edit_pane__date_selected" object="GtdEditPane" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="no_date_button"> + <property name="label" translatable="yes">None</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/data/ui/list-view.ui b/data/ui/list-view.ui index e82578e3..ab1bcc5a 100644 --- a/data/ui/list-view.ui +++ b/data/ui/list-view.ui @@ -2,124 +2,150 @@ <!-- Generated with glade 3.18.1 --> <interface> <requires lib="gtk+" version="3.16"/> - <template class="GtdListView" parent="GtkBox"> + <template class="GtdListView" parent="GtkOverlay"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="orientation">vertical</property> <child> - <object class="GtkScrolledWindow" id="scrolled_window"> + <object class="GtkBox" id="main_box"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hexpand">True</property> - <property name="vexpand">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> <child> - <object class="GtkViewport" id="viewport"> + <object class="GtkScrolledWindow" id="scrolled_window"> <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="shadow_type">none</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> <child> - <object class="GtkListBox" id="listbox"> + <object class="GtkViewport" id="viewport"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="valign">start</property> - <property name="hexpand">True</property> - <property name="selection_mode">none</property> - <style> - <class name="transparent" /> - </style> + <property name="shadow_type">none</property> + <child> + <object class="GtkListBox" id="listbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="valign">start</property> + <property name="hexpand">True</property> + <property name="selection_mode">none</property> + <signal name="row-activated" handler="gtd_list_view__row_activated" object="GtdListView" swapped="no" /> + <style> + <class name="transparent" /> + </style> + </object> + </child> </object> </child> </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkRevealer" id="revealer"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="transition_type">slide-up</property> <child> - <object class="GtkBox" id="box"> + <object class="GtkRevealer" id="revealer"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="orientation">vertical</property> + <property name="transition_type">slide-up</property> <child> - <object class="GtkSeparator" id="separator"> + <object class="GtkBox" id="box"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="hexpand">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="done_button"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="tooltip_text" translatable="yes">Show or hide completed tasks</property> - <property name="border_width">12</property> - <property name="relief">none</property> - <signal name="clicked" handler="gtd_list_view__done_button_clicked" object="GtdListView" swapped="no" /> + <property name="orientation">vertical</property> <child> - <object class="GtkBox" id="done_button_box"> + <object class="GtkSeparator" id="separator"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="spacing">12</property> - <child> - <object class="GtkImage" id="done_image"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="icon_name">zoom-in-symbolic</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> + <property name="hexpand">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="done_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Show or hide completed tasks</property> + <property name="border_width">12</property> + <property name="relief">none</property> + <signal name="clicked" handler="gtd_list_view__done_button_clicked" object="GtdListView" swapped="no" /> <child> - <object class="GtkLabel" id="done_label"> + <object class="GtkBox" id="done_button_box"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="hexpand">True</property> - <property name="label" translatable="yes">Done</property> - <property name="xalign">0</property> - <style> - <class name="dim-label"/> - </style> + <property name="spacing">12</property> + <child> + <object class="GtkImage" id="done_image"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">zoom-in-symbolic</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="done_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">Done</property> + <property name="xalign">0</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> </child> </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> </child> </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <child type="overlay"> + <object class="GtkRevealer" id="edit_revealer"> + <property name="visible">True</property> + <property name="halign">end</property> + <property name="transition_type">slide-left</property> + <property name="transition_duration">150</property> + <child> + <object class="GtdArrowFrame" id="arrow_frame"> + <property name="visible">True</property> + <child> + <object class="GtdEditPane" id="edit_pane"> + <property name="visible">True</property> + <signal name="edit-finished" handler="gtd_list_view__edit_task_finished" object="GtdListView" swapped="no" /> + </object> </child> </object> </child> </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> </child> </template> </interface> diff --git a/data/ui/source-selector.ui b/data/ui/source-selector.ui new file mode 100644 index 00000000..a653b3fc --- /dev/null +++ b/data/ui/source-selector.ui @@ -0,0 +1,232 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.18.1 --> +<interface> + <requires lib="gtk+" version="3.16"/> + <template class="GtdSourceSelectorDialog" parent="GtkDialog"> + <property name="can_focus">False</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox" id="box"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkStack" id="stack"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <child> + <object class="GtkBox" id="setup_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">center</property> + <property name="valign">center</property> + <property name="border_width">12</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="welcome_title_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Welcome</property> + <style> + <class name="welcome-title"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="welcome_secondary_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Login to online accounts to access your tasks</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="setup_scrolledwindow"> + <property name="width_request">400</property> + <property name="height_request">200</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkViewport" id="setup_viewport"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkListBox" id="setup_listbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="selection_mode">none</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="local_check"> + <property name="label" translatable="yes">Or you can just keep your tasks on this device</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="name">setup</property> + <property name="title" translatable="yes">Setup</property> + </packing> + </child> + <child> + <object class="GtkBox" id="default_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="border_width">12</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="default_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="label" translatable="yes">New task lists will be added to the selected source by default.</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="default_scrolledwindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkViewport" id="default_viewport"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkListBox" id="default_listbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="selection_mode">none</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="online_accounts_button"> + <property name="label" translatable="yes">Online Accounts</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="name">default</property> + <property name="title" translatable="yes">Default</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <child type="titlebar"> + <object class="GtkHeaderBar" id="headerbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="title">To Do Setup</property> + <child> + <object class="GtkButton" id="cancel_button"> + <property name="label" translatable="yes">Cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + </child> + <child> + <object class="GtkButton" id="done_button"> + <property name="label" translatable="yes">Done</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <style> + <class name="suggested-action"/> + </style> + </object> + <packing> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </template> +</interface> diff --git a/data/ui/task-row.ui b/data/ui/task-row.ui index 604657e8..2b84792c 100644 --- a/data/ui/task-row.ui +++ b/data/ui/task-row.ui @@ -6,6 +6,7 @@ <property name="width_request">100</property> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="activatable">True</property> <property name="selectable">False</property> <child> <object class="GtkRevealer" id="revealer"> @@ -143,6 +144,21 @@ </packing> </child> <child> + <object class="GtkLabel" id="task_date_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">1</property> + <style> + <class name="dim-label"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + <child> <object class="GtkLabel" id="task_list_label"> <property name="visible">False</property> <property name="can_focus">False</property> @@ -153,7 +169,7 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">3</property> + <property name="position">4</property> </packing> </child> </object> diff --git a/src/Makefile.am b/src/Makefile.am index c0362964..5b793b59 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,6 +15,10 @@ gnome_todo_SOURCES = \ $(BUILT_SOURCES) \ gtd-application.c \ gtd-application.h \ + gtd-arrow-frame.c \ + gtd-arrow-frame.h \ + gtd-edit-pane.c \ + gtd-edit-pane.h \ gtd-enums.h \ gtd-list-view.c \ gtd-list-view.h \ diff --git a/src/gtd-arrow-frame.c b/src/gtd-arrow-frame.c index f9c13e64..e02d9451 100644 --- a/src/gtd-arrow-frame.c +++ b/src/gtd-arrow-frame.c @@ -69,6 +69,7 @@ gtd_arrow_frame_get_property (GObject *object, switch (prop_id) { case PROP_TASK_ROW: + g_value_set_object (value, self->priv->row); break; default: @@ -87,6 +88,7 @@ gtd_arrow_frame_set_property (GObject *object, switch (prop_id) { case PROP_TASK_ROW: + gtd_arrow_frame_set_row (self, g_value_get_object (value)); break; default: @@ -94,6 +96,17 @@ gtd_arrow_frame_set_property (GObject *object, } } +static void +gtd_arrow_frame__row_destroyed (GtdTaskRow *row, + gpointer user_data) +{ + GtdArrowFramePrivate *priv; + + g_return_if_fail (GTD_IS_ARROW_FRAME (user_data)); + + gtd_arrow_frame_set_row (GTD_ARROW_FRAME (user_data), NULL); +} + static gint gtd_arrow_frame__get_row_y (GtdArrowFrame *frame) { @@ -373,7 +386,20 @@ gtd_arrow_frame_set_row (GtdArrowFrame *frame, { g_return_if_fail (GTD_IS_ARROW_FRAME (frame)); + if (frame->priv->row) + { + g_signal_handlers_disconnect_by_func (frame->priv->row, gtd_arrow_frame__row_destroyed, frame); + } + frame->priv->row = row; - gtk_widget_queue_draw (GTK_WIDGET (frame)); + if (row) + { + g_signal_connect (row, + "destroy", + G_CALLBACK (gtd_arrow_frame__row_destroyed), + frame); + + gtk_widget_queue_draw (GTK_WIDGET (frame)); + } } diff --git a/src/gtd-edit-pane.c b/src/gtd-edit-pane.c new file mode 100644 index 00000000..53ab4509 --- /dev/null +++ b/src/gtd-edit-pane.c @@ -0,0 +1,365 @@ +/* gtd-edit-pane.c + * + * Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "gtd-edit-pane.h" +#include "gtd-manager.h" +#include "gtd-task.h" + +#include <glib/gi18n.h> + +typedef struct +{ + GtkCalendar *calendar; + GtkLabel *date_label; + GtkTextView *notes_textview; + GtkComboBoxText *priority_combo; + + /* task bindings */ + GBinding *notes_binding; + GBinding *priority_binding; + + + GtdManager *manager; + GtdTask *task; +} GtdEditPanePrivate; + +struct _GtdEditPane +{ + GtkGrid parent; + + /*<private>*/ + GtdEditPanePrivate *priv; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GtdEditPane, gtd_edit_pane, GTK_TYPE_GRID) + +enum { + PROP_0, + PROP_MANAGER, + PROP_TASK, + LAST_PROP +}; + +enum { + EDIT_FINISHED, + NUM_SIGNALS +}; + +static guint signals[NUM_SIGNALS] = { 0, }; + +static void gtd_edit_pane__date_selected (GtkCalendar *calendar, + gpointer user_data); + +static void +gtd_edit_pane__close_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtdEditPanePrivate *priv; + + g_return_if_fail (GTD_IS_EDIT_PANE (user_data)); + + priv = GTD_EDIT_PANE (user_data)->priv; + + /* save the task */ + gtd_task_save (priv->task); + + g_signal_emit (user_data, signals[EDIT_FINISHED], 0, priv->task); +} + +static void +gtd_edit_pane_update_date (GtdEditPane *pane) +{ + GtdEditPanePrivate *priv; + GDateTime *dt; + gchar *text; + + g_return_if_fail (GTD_IS_EDIT_PANE (pane)); + + priv = pane->priv; + dt = priv->task ? gtd_task_get_due_date (priv->task) : NULL; + text = dt ? g_date_time_format (dt, "%x") : NULL; + + if (dt) + { + g_signal_handlers_block_by_func (priv->calendar, + gtd_edit_pane__date_selected, + pane); + + gtk_calendar_select_month (priv->calendar, + g_date_time_get_month (dt) - 1, + g_date_time_get_year (dt)); + gtk_calendar_select_day (priv->calendar, + g_date_time_get_day_of_month (dt)); + gtk_calendar_mark_day (priv->calendar, + g_date_time_get_day_of_month (dt)); + + g_signal_handlers_unblock_by_func (priv->calendar, + gtd_edit_pane__date_selected, + pane); + } + + gtk_label_set_label (priv->date_label, text ? text : _("No date set")); + + g_free (text); +} + +static void +gtd_edit_pane__date_selected (GtkCalendar *calendar, + gpointer user_data) +{ + GtdEditPanePrivate *priv; + GDateTime *new_dt; + gchar *text; + guint year; + guint month; + guint day; + + g_return_if_fail (GTD_IS_EDIT_PANE (user_data)); + + priv = GTD_EDIT_PANE (user_data)->priv; + + gtk_calendar_get_date (calendar, + &year, + &month, + &day); + + new_dt = g_date_time_new_local (year, + month + 1, + day, + 0, + 0, + 0); + + text = g_date_time_format (new_dt, "%x"); + + gtd_task_set_due_date (priv->task, new_dt); + gtk_label_set_label (priv->date_label, text); + + g_date_time_unref (new_dt); + g_free (text); +} + +static void +gtd_edit_pane_finalize (GObject *object) +{ + GtdEditPane *self = (GtdEditPane *)object; + GtdEditPanePrivate *priv = gtd_edit_pane_get_instance_private (self); + + G_OBJECT_CLASS (gtd_edit_pane_parent_class)->finalize (object); +} + +static void +gtd_edit_pane_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtdEditPane *self = GTD_EDIT_PANE (object); + + switch (prop_id) + { + case PROP_MANAGER: + g_value_set_object (value, self->priv->manager); + break; + + case PROP_TASK: + g_value_set_object (value, self->priv->task); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtd_edit_pane_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtdEditPane *self = GTD_EDIT_PANE (object); + + switch (prop_id) + { + case PROP_MANAGER: + self->priv->manager = g_value_get_object (value); + break; + + case PROP_TASK: + self->priv->task = g_value_get_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtd_edit_pane_class_init (GtdEditPaneClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = gtd_edit_pane_finalize; + object_class->get_property = gtd_edit_pane_get_property; + object_class->set_property = gtd_edit_pane_set_property; + + /** + * GtdEditPane::manager: + * + * A weak reference to the application's #GtdManager instance. + */ + g_object_class_install_property ( + object_class, + PROP_MANAGER, + g_param_spec_object ("manager", + _("Manager of this application"), + _("The manager of the application"), + GTD_TYPE_MANAGER, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + /** + * GtdEditPane::task: + * + * The task that is actually being edited. + */ + g_object_class_install_property ( + object_class, + PROP_TASK, + g_param_spec_object ("task", + _("Task being edited"), + _("The task that is actually being edited"), + GTD_TYPE_TASK, + G_PARAM_READWRITE)); + + /** + * GtdEditPane::edit-finished: + * + * Emitted when the the user finishes editing the task, i.e. the pane is closed. + */ + signals[EDIT_FINISHED] = g_signal_new ("edit-finished", + GTD_TYPE_EDIT_PANE, + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 1, + GTD_TYPE_TASK); + + /* template class */ + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/todo/ui/edit-pane.ui"); + + gtk_widget_class_bind_template_child_private (widget_class, GtdEditPane, calendar); + gtk_widget_class_bind_template_child_private (widget_class, GtdEditPane, date_label); + gtk_widget_class_bind_template_child_private (widget_class, GtdEditPane, notes_textview); + gtk_widget_class_bind_template_child_private (widget_class, GtdEditPane, priority_combo); + + gtk_widget_class_bind_template_callback (widget_class, gtd_edit_pane__close_button_clicked); + gtk_widget_class_bind_template_callback (widget_class, gtd_edit_pane__date_selected); +} + +static void +gtd_edit_pane_init (GtdEditPane *self) +{ + self->priv = gtd_edit_pane_get_instance_private (self); + + gtk_widget_init_template (GTK_WIDGET (self)); +} + +GtkWidget* +gtd_edit_pane_new (void) +{ + return g_object_new (GTD_TYPE_EDIT_PANE, NULL); +} + +/** + * gtd_edit_pane_get_task: + * @pane: a #GtdEditPane + * + * Retrieves the currently edited #GtdTask of %pane, or %NULL if none is set. + * + * Returns: (transfer none): the current #GtdTask being edited from %pane. + */ +GtdTask* +gtd_edit_pane_get_task (GtdEditPane *pane) +{ + g_return_val_if_fail (GTD_IS_EDIT_PANE (pane), NULL); + + return pane->priv->task; +} + +/** + * gtd_edit_pane_set_task: + * @pane: a #GtdEditPane + * @task: a #GtdTask or %NULL + * + * Sets %task as the currently editing task of %pane. + * + * Returns: + */ +void +gtd_edit_pane_set_task (GtdEditPane *pane, + GtdTask *task) +{ + GtdEditPanePrivate *priv; + + g_return_if_fail (GTD_IS_EDIT_PANE (pane)); + + priv = pane->priv; + + if (priv->task != task) + { + if (priv->task) + { + g_clear_pointer (&priv->notes_binding, g_binding_unbind); + g_clear_pointer (&priv->priority_binding, g_binding_unbind); + } + + priv->task = task; + + if (task) + { + /* due date */ + gtd_edit_pane_update_date (pane); + + /* description */ + gtk_text_buffer_set_text (gtk_text_view_get_buffer (priv->notes_textview), + gtd_task_get_description (task), + -1); + priv->notes_binding = g_object_bind_property (task, + "description", + gtk_text_view_get_buffer (priv->notes_textview), + "text", + G_BINDING_BIDIRECTIONAL); + + /* priority */ + gtk_combo_box_set_active (GTK_COMBO_BOX (priv->priority_combo), CLAMP (gtd_task_get_priority (task), + 0, + 3)); + priv->priority_binding = g_object_bind_property (task, + "priority", + priv->priority_combo, + "active", + G_BINDING_BIDIRECTIONAL); + } + + g_object_notify (G_OBJECT (pane), "task"); + } +} diff --git a/src/gtd-edit-pane.h b/src/gtd-edit-pane.h new file mode 100644 index 00000000..08b0f679 --- /dev/null +++ b/src/gtd-edit-pane.h @@ -0,0 +1,42 @@ +/* gtd-edit-pane.h + * + * Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GTD_EDIT_PANE_H +#define GTD_EDIT_PANE_H + +#include "gtd-types.h" + +#include <glib-object.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GTD_TYPE_EDIT_PANE (gtd_edit_pane_get_type()) + +G_DECLARE_FINAL_TYPE (GtdEditPane, gtd_edit_pane, GTD, EDIT_PANE, GtkGrid) + +GtkWidget* gtd_edit_pane_new (void); + +GtdTask* gtd_edit_pane_get_task (GtdEditPane *pane); + +void gtd_edit_pane_set_task (GtdEditPane *pane, + GtdTask *task); + +G_END_DECLS + +#endif /* GTD_EDIT_PANE_H */ diff --git a/src/gtd-list-view.c b/src/gtd-list-view.c index be065384..dc5816be 100644 --- a/src/gtd-list-view.c +++ b/src/gtd-list-view.c @@ -16,6 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "gtd-arrow-frame.h" +#include "gtd-edit-pane.h" #include "gtd-list-view.h" #include "gtd-manager.h" #include "gtd-task.h" @@ -28,6 +30,9 @@ typedef struct { + GtdArrowFrame *arrow_frame; + GtdEditPane *edit_pane; + GtkRevealer *edit_revealer; GtkListBox *listbox; GtdTaskRow *new_task_row; GtkRevealer *revealer; @@ -51,7 +56,7 @@ typedef struct struct _GtdListView { - GtkBox parent; + GtkOverlay parent; /*<private>*/ GtdListViewPrivate *priv; @@ -64,7 +69,7 @@ static void gtd_list_view__task_completed (GObject GParamSpec *spec, gpointer user_data); -G_DEFINE_TYPE_WITH_PRIVATE (GtdListView, gtd_list_view, GTK_TYPE_BOX) +G_DEFINE_TYPE_WITH_PRIVATE (GtdListView, gtd_list_view, GTK_TYPE_OVERLAY) enum { PROP_0, @@ -76,6 +81,26 @@ enum { }; static void +gtd_list_view__edit_task_finished (GtdEditPane *pane, + GtdTask *task, + gpointer user_data) +{ + GtdListViewPrivate *priv; + + g_return_if_fail (GTD_IS_TASK (task)); + g_return_if_fail (GTD_IS_EDIT_PANE (pane)); + g_return_if_fail (GTD_IS_LIST_VIEW (user_data)); + + priv = GTD_LIST_VIEW (user_data)->priv; + + gtk_revealer_set_reveal_child (priv->edit_revealer, FALSE); + + gtd_manager_update_task (priv->manager, task); + + gtk_list_box_invalidate_sort (priv->listbox); +} + +static void gtd_list_view__color_changed (GObject *object, GParamSpec *spec, gpointer user_data) @@ -193,6 +218,7 @@ gtd_list_view__clear_list (GtdListView *view) g_return_if_fail (GTD_IS_LIST_VIEW (view)); view->priv->complete_tasks = 0; + gtd_arrow_frame_set_row (view->priv->arrow_frame, NULL); children = gtk_container_get_children (GTK_CONTAINER (view->priv->listbox)); @@ -208,11 +234,28 @@ gtd_list_view__clear_list (GtdListView *view) } gtk_revealer_set_reveal_child (view->priv->revealer, FALSE); + gtk_revealer_set_reveal_child (view->priv->edit_revealer, FALSE); g_list_free (children); } static void +gtd_list_view__row_activated (GtkListBox *listbox, + GtdTaskRow *row, + gpointer user_data) +{ + GtdListViewPrivate *priv = GTD_LIST_VIEW (user_data)->priv; + + if (row == priv->new_task_row) + return; + + gtk_revealer_set_reveal_child (priv->edit_revealer, TRUE); + gtd_arrow_frame_set_row (priv->arrow_frame, row); + + gtd_edit_pane_set_task (priv->edit_pane, gtd_task_row_get_task (row)); +} + +static void gtd_list_view__add_task (GtdListView *view, GtdTask *task) { @@ -510,6 +553,9 @@ gtd_list_view_class_init (GtdListViewClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/todo/ui/list-view.ui"); + gtk_widget_class_bind_template_child_private (widget_class, GtdListView, arrow_frame); + gtk_widget_class_bind_template_child_private (widget_class, GtdListView, edit_pane); + gtk_widget_class_bind_template_child_private (widget_class, GtdListView, edit_revealer); gtk_widget_class_bind_template_child_private (widget_class, GtdListView, listbox); gtk_widget_class_bind_template_child_private (widget_class, GtdListView, revealer); gtk_widget_class_bind_template_child_private (widget_class, GtdListView, done_image); @@ -517,6 +563,8 @@ gtd_list_view_class_init (GtdListViewClass *klass) gtk_widget_class_bind_template_child_private (widget_class, GtdListView, viewport); gtk_widget_class_bind_template_callback (widget_class, gtd_list_view__done_button_clicked); + gtk_widget_class_bind_template_callback (widget_class, gtd_list_view__edit_task_finished); + gtk_widget_class_bind_template_callback (widget_class, gtd_list_view__row_activated); } static void diff --git a/src/gtd-list-view.h b/src/gtd-list-view.h index f5ade336..b522b151 100644 --- a/src/gtd-list-view.h +++ b/src/gtd-list-view.h @@ -27,7 +27,7 @@ G_BEGIN_DECLS #define GTD_TYPE_LIST_VIEW (gtd_list_view_get_type()) -G_DECLARE_FINAL_TYPE (GtdListView, gtd_list_view, GTD, LIST_VIEW, GtkBox) +G_DECLARE_FINAL_TYPE (GtdListView, gtd_list_view, GTD, LIST_VIEW, GtkOverlay) GtkWidget* gtd_list_view_new (void); diff --git a/src/gtd-task-row.c b/src/gtd-task-row.c index 9dcf324a..2ad23450 100644 --- a/src/gtd-task-row.c +++ b/src/gtd-task-row.c @@ -35,6 +35,7 @@ typedef struct /* task widgets */ GtkEntry *title_entry; + GtkLabel *task_date_label; GtkLabel *task_list_label; GtkSpinner *task_loading_spinner; GtkLabel *title_label; @@ -71,6 +72,65 @@ enum { static guint signals[NUM_SIGNALS] = { 0, }; +static gboolean +gtd_task_row__date_changed_binding (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + GtdTaskRowPrivate *priv; + GDateTime *dt; + gchar *new_label = NULL; + + g_return_val_if_fail (GTD_IS_TASK_ROW (user_data), FALSE); + + priv = GTD_TASK_ROW (user_data)->priv; + dt = g_value_get_boxed (from_value); + + if (dt) + { + GDateTime *today = g_date_time_new_now_local (); + new_label = g_date_time_format (dt, "%x"); + + if (g_date_time_get_year (dt) == g_date_time_get_year (today) && + g_date_time_get_month (dt) == g_date_time_get_month (today)) + { + if (g_date_time_get_day_of_month (dt) == g_date_time_get_day_of_month (today)) + { + new_label = g_strdup (_("Today")); + } + else if (g_date_time_get_day_of_month (dt) == g_date_time_get_day_of_month (today) + 1) + { + new_label = g_strdup (_("Tomorrow")); + } + else if (g_date_time_get_day_of_month (dt) == g_date_time_get_day_of_month (today) - 1) + { + new_label = g_strdup (_("Yesterday")); + } + else if (g_date_time_get_day_of_year (dt) > g_date_time_get_day_of_month (today) && + g_date_time_get_day_of_year (dt) < g_date_time_get_day_of_month (today) + 7) + { + new_label = g_date_time_format (dt, "%A"); + } + else + { + new_label = g_date_time_format (dt, "%x"); + } + } + + } + else + { + new_label = g_strdup (_("No date set")); + } + + g_value_set_string (to_value, new_label); + + g_free (new_label); + + return TRUE; +} + static GtdTask* gtd_task_row__create_task_for_name (const gchar *name) { @@ -120,10 +180,6 @@ gtd_task_row__focus_in (GtkWidget *widget, gtk_stack_set_visible_child_name (priv->new_task_stack, "entry"); gtk_widget_grab_focus (GTK_WIDGET (priv->new_task_entry)); } - else - { - g_signal_emit (widget, signals[ENTER], 0); - } return FALSE; } @@ -233,10 +289,19 @@ gtd_task_row_set_property (GObject *object, } static void +gtd_task_row_activate (GtkListBoxRow *row) +{ + GTK_LIST_BOX_ROW_CLASS (gtd_task_row_parent_class)->activate (row); + + g_signal_emit (row, signals[ENTER], 0); +} + +static void gtd_task_row_class_init (GtdTaskRowClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkListBoxRowClass *row_class = GTK_LIST_BOX_ROW_CLASS (klass); object_class->finalize = gtd_task_row_finalize; object_class->get_property = gtd_task_row_get_property; @@ -245,6 +310,8 @@ gtd_task_row_class_init (GtdTaskRowClass *klass) widget_class->focus_in_event = gtd_task_row__focus_in; widget_class->key_press_event = gtd_task_row__key_press_event; + row_class->activate = gtd_task_row_activate; + /** * GtdTaskRow::new-task-mode: * @@ -341,6 +408,7 @@ gtd_task_row_class_init (GtdTaskRowClass *klass) gtk_widget_class_bind_template_child_private (widget_class, GtdTaskRow, new_task_entry); gtk_widget_class_bind_template_child_private (widget_class, GtdTaskRow, new_task_stack); gtk_widget_class_bind_template_child_private (widget_class, GtdTaskRow, revealer); + gtk_widget_class_bind_template_child_private (widget_class, GtdTaskRow, task_date_label); gtk_widget_class_bind_template_child_private (widget_class, GtdTaskRow, task_list_label); gtk_widget_class_bind_template_child_private (widget_class, GtdTaskRow, task_loading_spinner); gtk_widget_class_bind_template_child_private (widget_class, GtdTaskRow, title_entry); @@ -460,6 +528,16 @@ gtd_task_row_set_task (GtdTaskRow *row, row->priv->task_loading_spinner, "visible", G_BINDING_INVERT_BOOLEAN | G_BINDING_SYNC_CREATE); + + g_object_bind_property_full (task, + "due-date", + row->priv->task_date_label, + "label", + G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE, + gtd_task_row__date_changed_binding, + NULL, + row, + NULL); } g_object_notify (G_OBJECT (row), "task"); diff --git a/src/gtd-task.c b/src/gtd-task.c index 3543b82b..fc219911 100644 --- a/src/gtd-task.c +++ b/src/gtd-task.c @@ -617,6 +617,7 @@ gtd_task_set_due_date (GtdTask *task, { ECalComponentDateTime comp_dt; icaltimetype *idt; + gboolean changed = FALSE; comp_dt.value = NULL; comp_dt.tzid = NULL; @@ -645,14 +646,14 @@ gtd_task_set_due_date (GtdTask *task, g_date_time_unref (dt); - g_object_notify (G_OBJECT (task), "due-date"); + changed = TRUE; } else if (!dt) { idt = NULL; comp_dt.tzid = NULL; - g_object_notify (G_OBJECT (task), "due-date"); + changed = TRUE; } comp_dt.value = idt; @@ -660,6 +661,9 @@ gtd_task_set_due_date (GtdTask *task, e_cal_component_set_dtend (task->priv->component, &comp_dt); e_cal_component_free_datetime (&comp_dt); + + if (changed) + g_object_notify (G_OBJECT (task), "due-date"); } if (current_dt) |