Added config options for call and sms ringtones
[gregoa/zavai.git] / src / calendar.vala
1 /*
2  * widgets/calendar - zavai calendar widget
3  *
4  * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 namespace zavai {
22 namespace widgets {
23
24 private string month_path(int year, int month)
25 {
26         return "%s/cal/%04d/%02d".printf(zavai.config.homedir, year, month);
27 }
28
29 private string day_path(int year, int month, int day)
30 {
31         return "%s/%02d.txt".printf(month_path(year, month), day);
32 }
33
34
35 public class FileNotes : Gtk.ScrolledWindow
36 {
37         protected Gtk.TextBuffer text_buffer;
38         protected Gtk.TextView text;
39         protected bool text_dirty;
40         protected string fname;
41
42         public FileNotes()
43         {
44                 fname = null;
45                 text_dirty = false;
46                 text_buffer = new Gtk.TextBuffer(null);
47                 text_buffer.changed += on_textbuffer_changed;
48                 text = new Gtk.TextView.with_buffer(text_buffer);
49                 text.wrap_mode = Gtk.WrapMode.WORD;
50                 text.cursor_visible = true;
51                 text.editable = true;
52
53                 set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
54                 add(text);
55         }
56         
57         private void on_textbuffer_changed()
58         {
59                 text_dirty = true;
60         }
61
62         public void load(string new_fname)
63         {
64                 save();
65                 fname = new_fname;
66
67                 if (!FileUtils.test (fname, FileTest.IS_REGULAR))
68                         text_buffer.text = "";
69                 else
70                 {
71                         try {
72                                 string text;
73                                 FileUtils.get_contents(fname, out text);
74                                 text_buffer.text = text;
75                         } catch (FileError e) {
76                                 zavai.log.error(e.message);
77                                 text_buffer.text = "";
78                         }
79                 }
80
81                 // Scroll to beginning
82                 Gtk.TextIter iter;
83                 text_buffer.get_iter_at_offset(out iter, 0);
84                 Gtk.TextMark mark = text_buffer.create_mark(null, iter, true);
85                 text.scroll_mark_onscreen(mark);
86
87                 text_dirty = false;
88         }
89
90         public void save()
91         {
92                 if (fname == null) return;
93                 if (text_dirty == false) return;
94
95                 string mpath = Path.get_dirname(fname);
96                 if (DirUtils.create_with_parents(mpath, 0777) < 0)
97                 {
98                         zavai.log.error("Cannot create directory " + mpath);
99                         return;
100                 }
101                 try {
102                         if (text_buffer.text == "")
103                         {
104                                 if (FileUtils.test(fname, FileTest.EXISTS))
105                                         FileUtils.unlink(fname);
106                         } else {
107                                 FileUtils.set_contents(fname, text_buffer.text);
108                         }
109                 } catch (FileError e) {
110                         zavai.log.error(e.message);
111                 }
112                 text_dirty = false;
113         }
114 }
115
116 public class Next30 : Gtk.ScrolledWindow
117 {
118         protected Gtk.ListStore model;
119         protected Gtk.TreeView list;
120         public signal void selected(int year, int month, int day);
121
122         public Next30()
123         {
124                 set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
125                 model = new Gtk.ListStore(5, typeof(string), typeof(string), typeof(int), typeof(int), typeof(int));
126                 list = new Gtk.TreeView.with_model(model);
127                 list.insert_column_with_attributes (-1, "Day", new Gtk.CellRendererText(), "text", 0);
128                 list.insert_column_with_attributes (-1, "Notes", new Gtk.CellRendererText(), "text", 1);
129                 add(list);
130
131                 list.cursor_changed += on_row_selected;
132         }
133
134         //private void on_row_selected(Gtk.TreeView tv, Gtk.TreePath path, Gtk.TreeViewColumn column)
135         private void on_row_selected(Gtk.TreeView tv)
136         {
137                 Gtk.TreePath path;
138                 list.get_cursor(out path, null);
139
140                 Gtk.TreeIter iter;
141
142                 if (!model.get_iter(out iter, path)) return;
143                 Value year, month, day;
144                 model.get_value(iter, 2, out year);
145                 model.get_value(iter, 3, out month);
146                 model.get_value(iter, 4, out day);
147                 selected((int)year, (int)month, (int)day);
148         }
149
150         protected void add_day(Date date, string notes)
151         {
152                 var buffer = new char[64];
153                 date.strftime(buffer, "%d %a");
154                 Gtk.TreeIter iter;
155         model.insert_with_values(out iter, -1,
156             0, (string)buffer,
157             1, notes,
158             2, date.get_year(),
159             3, date.get_month(),
160             4, date.get_day(),
161             -1);
162         }
163
164         public void update(Date start)
165         {
166                 Date date = start;
167                 model.clear();
168                 for (uint i = 0; i < 30; ++i)
169                 {
170                         string path = day_path(date.get_year(), date.get_month(), date.get_day());
171                         string text;
172                         if (!FileUtils.test (path, FileTest.IS_REGULAR))
173                                 text = "";
174                         else
175                         {
176                                 try {
177                                         FileUtils.get_contents(path, out text);
178                                 } catch (FileError e) {
179                                         text = "";
180                                 }
181                         }
182                         if (i == 0 || text != "")
183                         {
184                                 add_day(date, text);
185                         }
186                         date.add_days(1);
187                 }
188         }
189 }
190
191 public class Calendar : Gtk.VBox
192 {
193         protected Gtk.Calendar calendar;
194         protected Gtk.Notebook notebook;
195         protected Gtk.Notebook day_notebook;
196         protected FileNotes month_notes;
197         protected FileNotes day_notes;
198         protected FileNotes general_notes;
199         protected Next30 next_30;
200         protected int cur_year;
201         protected int cur_month;
202         protected int cur_day;
203
204         public Calendar()
205         {
206                 calendar = new Gtk.Calendar();
207                 calendar.day_selected += on_day_selected;
208                 calendar.month_changed += on_month_changed;
209                 pack_start(calendar, false, false, 0);
210
211                 notebook = new Gtk.Notebook();
212
213                 day_notebook = new Gtk.Notebook();
214                 next_30 = new Next30();
215                 next_30.selected += on_next30_selected;
216                 day_notebook.append_page(next_30, new Gtk.Label("Next 30"));
217                 day_notes = new FileNotes();
218                 day_notebook.append_page(day_notes, new Gtk.Label("Day"));
219                 notebook.append_page(day_notebook, new Gtk.Label("Day"));
220                 day_notebook.show_tabs = false; 
221
222                 month_notes = new FileNotes();
223                 notebook.append_page(month_notes, new Gtk.Label("Month"));
224                 general_notes = new FileNotes();
225                 general_notes.load(zavai.config.homedir + "/cal/notes.txt");
226                 notebook.append_page(general_notes, new Gtk.Label("General"));
227
228                 pack_start(notebook, true, true, 0);
229
230                 on_month_changed();
231                 on_day_selected();
232         }
233
234         private void on_next30_selected(int year, int month, int day)
235         {
236                 // Select this day in the calendar
237                 calendar.year = year;
238                 calendar.month = month-1;
239                 calendar.day = day;
240
241                 // View the day notes
242                 day_notebook.set_current_page(1);
243
244                 // TODO: when clicking on calendar, show next30 again
245         }
246
247         private void on_month_changed()
248         {
249                 flush();
250                 calendar.clear_marks();
251                 string mpath = month_path(calendar.year, calendar.month + 1);
252                 month_notes.load(mpath + "/00.txt");
253                 Dir dir;
254                 try {
255                         dir = Dir.open(mpath);
256                 } catch (FileError e) {
257                         zavai.log.error(e.message);
258                         return;
259                 }
260                 while (true)
261                 {
262                         var d = dir.read_name();
263                         if (d == null) break;
264                         if (d[0].isdigit() && d.has_suffix(".txt") && d.size() == 6)
265                         {
266                                 calendar.mark_day((int)d.to_ulong(null, 10));
267                         }
268                 }
269         }
270
271         private void on_day_selected()
272         {
273                 cur_year = calendar.year;
274                 cur_month = calendar.month + 1;
275                 cur_day = calendar.day;
276
277                 string path = day_path(cur_year, cur_month, cur_day);
278                 day_notes.load(path);
279
280                 string mpath = month_path(cur_year, cur_month);
281                 month_notes.load(mpath + "/00.txt");
282
283                 Date date = Date();
284                 date.set_dmy((DateDay)cur_day, cur_month, (DateYear)cur_year);
285                 next_30.update(date);
286                 day_notebook.set_current_page(0);
287         }
288
289         public void flush()
290         {
291                 day_notes.save();
292                 month_notes.save();
293                 general_notes.save();
294         }
295
296         public void show_today()
297         {
298                 // Go to current date
299                 var now = Time.local(time_t());
300                 calendar.year = now.year + 1900;
301                 calendar.month = now.month;
302                 calendar.day = now.day;
303                 on_month_changed();
304         }
305 }
306
307 }
308 }