Store date info in the next30 list items
[gregoa/zavai.git] / src / widgets / 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 public class FileNotes : Gtk.ScrolledWindow
25 {
26         protected Gtk.TextBuffer text_buffer;
27         protected Gtk.TextView text;
28         protected bool text_dirty;
29         protected string fname;
30
31         public FileNotes()
32         {
33                 fname = null;
34                 text_dirty = false;
35                 text_buffer = new Gtk.TextBuffer(null);
36                 text_buffer.changed += on_textbuffer_changed;
37                 text = new Gtk.TextView.with_buffer(text_buffer);
38                 text.wrap_mode = Gtk.WrapMode.WORD;
39                 text.cursor_visible = true;
40                 text.editable = true;
41
42                 set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
43                 add(text);
44         }
45         
46         private void on_textbuffer_changed()
47         {
48                 text_dirty = true;
49         }
50
51         public void load(string new_fname)
52         {
53                 save();
54                 fname = new_fname;
55
56                 if (!FileUtils.test (fname, FileTest.IS_REGULAR))
57                         text_buffer.text = "";
58                 else
59                 {
60                         try {
61                                 string text;
62                                 FileUtils.get_contents(fname, out text);
63                                 text_buffer.text = text;
64                         } catch (FileError e) {
65                                 zavai.log.error(e.message);
66                                 text_buffer.text = "";
67                         }
68                 }
69
70                 // Scroll to beginning
71                 Gtk.TextIter iter;
72                 text_buffer.get_iter_at_offset(out iter, 0);
73                 Gtk.TextMark mark = text_buffer.create_mark(null, iter, true);
74                 text.scroll_mark_onscreen(mark);
75
76                 text_dirty = false;
77         }
78
79         public void save()
80         {
81                 if (fname == null) return;
82                 if (text_dirty == false) return;
83
84                 string mpath = Path.get_dirname(fname);
85                 if (DirUtils.create_with_parents(mpath, 0777) < 0)
86                 {
87                         zavai.log.error("Cannot create directory " + mpath);
88                         return;
89                 }
90                 try {
91                         if (text_buffer.text == "")
92                         {
93                                 if (FileUtils.test(fname, FileTest.EXISTS))
94                                         FileUtils.unlink(fname);
95                         } else {
96                                 FileUtils.set_contents(fname, text_buffer.text);
97                         }
98                 } catch (FileError e) {
99                         zavai.log.error(e.message);
100                 }
101                 text_dirty = false;
102         }
103 }
104
105 public class Next30 : Gtk.ScrolledWindow
106 {
107         protected Gtk.ListStore model;
108         protected Gtk.TreeView list;
109
110         public Next30()
111         {
112                 set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
113                 model = new Gtk.ListStore(5, typeof(string), typeof(string), typeof(int), typeof(int), typeof(int));
114                 list = new Gtk.TreeView.with_model(model);
115                 list.insert_column_with_attributes (-1, "Day", new Gtk.CellRendererText(), "text", 0);
116                 list.insert_column_with_attributes (-1, "Notes", new Gtk.CellRendererText(), "text", 1);
117                 add(list);
118         }
119
120         public void clear()
121         {
122                 model.clear();
123         }
124
125         public void add_day(Date date, string notes)
126         {
127                 var buffer = new char[64];
128                 date.strftime(buffer, "%d %a");
129                 Gtk.TreeIter iter;
130                 model.append (out iter);
131                 model.set(iter, 0, (string)buffer);
132                 model.set(iter, 1, notes);
133                 model.set(iter, 2, date.get_day());
134                 model.set(iter, 3, date.get_month());
135                 model.set(iter, 4, date.get_year());
136         }
137 }
138
139 public class Calendar : Gtk.VBox
140 {
141         protected Gtk.Calendar calendar;
142         protected Gtk.Notebook notebook;
143         protected FileNotes month_notes;
144         protected FileNotes day_notes;
145         protected FileNotes general_notes;
146         protected Next30 next_30;
147         protected int cur_year;
148         protected int cur_month;
149         protected int cur_day;
150         protected Regex re_dayfile;
151
152         public Calendar()
153         {
154                 calendar = new Gtk.Calendar();
155                 calendar.day_selected += on_day_selected;
156                 calendar.month_changed += on_month_changed;
157                 pack_start(calendar, false, false, 0);
158
159                 notebook = new Gtk.Notebook();
160
161                 next_30 = new Next30();
162                 notebook.append_page(next_30, new Gtk.Label("Next 30"));
163                 day_notes = new FileNotes();
164                 notebook.append_page(day_notes, new Gtk.Label("Day"));
165                 month_notes = new FileNotes();
166                 notebook.append_page(month_notes, new Gtk.Label("Month"));
167                 general_notes = new FileNotes();
168                 general_notes.load(zavai.config.homedir + "/cal/notes.txt");
169                 notebook.append_page(general_notes, new Gtk.Label("General"));
170
171                 pack_start(notebook, true, true, 0);
172
173                 re_dayfile = new Regex("[0-9][0-9]\\.txt");
174
175                 on_month_changed();
176         }
177
178         private string month_path(int year, int month)
179         {
180                 return "%s/cal/%04d/%02d".printf(zavai.config.homedir, year, month);
181         }
182
183         private string day_path(int year, int month, int day)
184         {
185                 return "%s/%02d.txt".printf(month_path(year, month), day);
186         }
187
188         private void on_month_changed()
189         {
190                 flush();
191                 calendar.clear_marks();
192                 string mpath = month_path(calendar.year, calendar.month + 1);
193                 month_notes.load(mpath + "/00.txt");
194                 Dir dir;
195                 try {
196                         dir = Dir.open(mpath);
197                 } catch (FileError e) {
198                         zavai.log.error(e.message);
199                         return;
200                 }
201                 while (true)
202                 {
203                         var d = dir.read_name();
204                         if (d == null) break;
205                         if (re_dayfile.match(d))
206                         {
207                                 calendar.mark_day((int)d.to_ulong(null, 10));
208                         }
209                 }
210         }
211
212         private void on_day_selected()
213         {
214                 cur_year = calendar.year;
215                 cur_month = calendar.month + 1;
216                 cur_day = calendar.day;
217
218                 string path = day_path(cur_year, cur_month, cur_day);
219                 day_notes.load(path);
220
221                 string mpath = month_path(cur_year, cur_month);
222                 month_notes.load(mpath + "/00.txt");
223
224                 next_30.clear();
225                 Date date = Date();
226                 date.set_dmy((DateDay)cur_day, cur_month, (DateYear)cur_year);
227                 for (uint i = 0; i < 30; ++i)
228                 {
229                         path = day_path(date.get_year(), date.get_month(), date.get_day());
230                         string text;
231                         if (!FileUtils.test (path, FileTest.IS_REGULAR))
232                                 text = "";
233                         else
234                         {
235                                 try {
236                                         FileUtils.get_contents(path, out text);
237                                 } catch (FileError e) {
238                                         text = "";
239                                 }
240                         }
241                         if (text != "")
242                         {
243                                 next_30.add_day(date, text);
244                         }
245                         date.add_days(1);
246                 }
247         }
248
249         public void flush()
250         {
251                 day_notes.save();
252                 month_notes.save();
253                 general_notes.save();
254         }
255
256         public void show_today()
257         {
258                 // Go to current date
259                 var now = Time.local(time_t());
260                 calendar.year = now.year + 1900;
261                 calendar.month = now.month;
262                 calendar.day = now.day;
263                 on_month_changed();
264         }
265 }
266
267 }
268 }