8f2c662717a8ecb00479b6f88346a3474ce2b0a5
[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(2, typeof(string), typeof(string));
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(string day, string notes)
126         {
127                 Gtk.TreeIter iter;
128                 model.append (out iter);
129                 model.set(iter, 0, day);
130                 model.set(iter, 1, notes);
131         }
132 }
133
134 public class Calendar : Gtk.VBox
135 {
136         protected Gtk.Calendar calendar;
137         protected Gtk.Notebook notebook;
138         protected FileNotes month_notes;
139         protected FileNotes day_notes;
140         protected FileNotes general_notes;
141         protected Next30 next_30;
142         protected int cur_year;
143         protected int cur_month;
144         protected int cur_day;
145         protected Regex re_dayfile;
146
147         public Calendar()
148         {
149                 calendar = new Gtk.Calendar();
150                 calendar.day_selected += on_day_selected;
151                 calendar.month_changed += on_month_changed;
152                 pack_start(calendar, false, false, 0);
153
154                 notebook = new Gtk.Notebook();
155
156                 day_notes = new FileNotes();
157                 notebook.append_page(day_notes, new Gtk.Label("Day"));
158                 month_notes = new FileNotes();
159                 notebook.append_page(month_notes, new Gtk.Label("Month"));
160                 general_notes = new FileNotes();
161                 general_notes.load(zavai.config.homedir + "/cal/notes.txt");
162                 notebook.append_page(general_notes, new Gtk.Label("General"));
163                 next_30 = new Next30();
164                 notebook.append_page(next_30, new Gtk.Label("Next 30"));
165
166                 pack_start(notebook, true, true, 0);
167
168                 re_dayfile = new Regex("[0-9][0-9]\\.txt");
169
170                 on_month_changed();
171         }
172
173         private string month_path(int year, int month)
174         {
175                 return "%s/cal/%04d/%02d".printf(zavai.config.homedir, year, month);
176         }
177
178         private string day_path(int year, int month, int day)
179         {
180                 return "%s/%02d.txt".printf(month_path(year, month), day);
181         }
182
183         private void on_month_changed()
184         {
185                 flush();
186                 calendar.clear_marks();
187                 string mpath = month_path(calendar.year, calendar.month + 1);
188                 month_notes.load(mpath + "/00.txt");
189                 Dir dir;
190                 try {
191                         dir = Dir.open(mpath);
192                 } catch (FileError e) {
193                         zavai.log.error(e.message);
194                         return;
195                 }
196                 while (true)
197                 {
198                         var d = dir.read_name();
199                         if (d == null) break;
200                         if (re_dayfile.match(d))
201                         {
202                                 calendar.mark_day((int)d.to_ulong(null, 10));
203                         }
204                 }
205         }
206
207         private void on_day_selected()
208         {
209                 cur_year = calendar.year;
210                 cur_month = calendar.month + 1;
211                 cur_day = calendar.day;
212
213                 string path = day_path(cur_year, cur_month, cur_day);
214                 day_notes.load(path);
215
216                 string mpath = month_path(cur_year, cur_month);
217                 month_notes.load(mpath + "/00.txt");
218
219                 next_30.clear();
220                 Date date = Date();
221                 date.set_dmy((DateDay)cur_day, cur_month, (DateYear)cur_year);
222                 var buffer = new char[64];
223                 for (uint i = 0; i < 30; ++i)
224                 {
225                         path = day_path(date.get_year(), date.get_month(), date.get_day());
226                         string text;
227                         if (!FileUtils.test (path, FileTest.IS_REGULAR))
228                                 text = "";
229                         else
230                         {
231                                 try {
232                                         FileUtils.get_contents(path, out text);
233                                 } catch (FileError e) {
234                                         text = "";
235                                 }
236                         }
237                         if (text != "")
238                         {
239                                 date.strftime(buffer, "%d %a");
240                                 next_30.add_day((string)buffer, text);
241                         }
242                         date.add_days(1);
243                 }
244         }
245
246         public void flush()
247         {
248                 day_notes.save();
249                 month_notes.save();
250                 general_notes.save();
251         }
252
253         public void show_today()
254         {
255                 // Go to current date
256                 var now = Time.local(time_t());
257                 calendar.year = now.year + 1900;
258                 calendar.month = now.month;
259                 calendar.day = now.day;
260                 on_month_changed();
261         }
262 }
263
264 }
265 }