/* * widgets/calendar - zavai calendar widget * * Copyright (C) 2009 Enrico Zini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ namespace zavai { namespace widgets { private string month_path(int year, int month) { return "%s/cal/%04d/%02d".printf(zavai.config.homedir, year, month); } private string day_path(int year, int month, int day) { return "%s/%02d.txt".printf(month_path(year, month), day); } public class FileNotes : Gtk.ScrolledWindow { protected Gtk.TextBuffer text_buffer; protected Gtk.TextView text; protected bool text_dirty; protected string fname; public FileNotes() { fname = null; text_dirty = false; text_buffer = new Gtk.TextBuffer(null); text_buffer.changed += on_textbuffer_changed; text = new Gtk.TextView.with_buffer(text_buffer); text.wrap_mode = Gtk.WrapMode.WORD; text.cursor_visible = true; text.editable = true; set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); add(text); } private void on_textbuffer_changed() { text_dirty = true; } public void load(string new_fname) { save(); fname = new_fname; if (!FileUtils.test (fname, FileTest.IS_REGULAR)) text_buffer.text = ""; else { try { string text; FileUtils.get_contents(fname, out text); text_buffer.text = text; } catch (FileError e) { zavai.log.error(e.message); text_buffer.text = ""; } } // Scroll to beginning Gtk.TextIter iter; text_buffer.get_iter_at_offset(out iter, 0); Gtk.TextMark mark = text_buffer.create_mark(null, iter, true); text.scroll_mark_onscreen(mark); text_dirty = false; } public void save() { if (fname == null) return; if (text_dirty == false) return; string mpath = Path.get_dirname(fname); if (DirUtils.create_with_parents(mpath, 0777) < 0) { zavai.log.error("Cannot create directory " + mpath); return; } try { if (text_buffer.text == "") { if (FileUtils.test(fname, FileTest.EXISTS)) FileUtils.unlink(fname); } else { FileUtils.set_contents(fname, text_buffer.text); } } catch (FileError e) { zavai.log.error(e.message); } text_dirty = false; } } public class Next30 : Gtk.ScrolledWindow { protected Gtk.ListStore model; protected Gtk.TreeView list; public signal void selected(int year, int month, int day); public Next30() { set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); model = new Gtk.ListStore(5, typeof(string), typeof(string), typeof(int), typeof(int), typeof(int)); list = new Gtk.TreeView.with_model(model); list.insert_column_with_attributes (-1, "Day", new Gtk.CellRendererText(), "text", 0); list.insert_column_with_attributes (-1, "Notes", new Gtk.CellRendererText(), "text", 1); add(list); list.cursor_changed += on_row_selected; } //private void on_row_selected(Gtk.TreeView tv, Gtk.TreePath path, Gtk.TreeViewColumn column) private void on_row_selected(Gtk.TreeView tv) { Gtk.TreePath path; list.get_cursor(out path, null); Gtk.TreeIter iter; if (!model.get_iter(out iter, path)) return; Value year, month, day; model.get_value(iter, 2, out year); model.get_value(iter, 3, out month); model.get_value(iter, 4, out day); selected((int)year, (int)month, (int)day); } protected void add_day(Date date, string notes) { var buffer = new char[64]; date.strftime(buffer, "%d %a"); Gtk.TreeIter iter; model.append (out iter); model.set(iter, 0, (string)buffer); model.set(iter, 1, notes); model.set(iter, 2, date.get_year()); model.set(iter, 3, date.get_month()); model.set(iter, 4, date.get_day()); } public void update(Date start) { Date date = start; model.clear(); for (uint i = 0; i < 30; ++i) { string path = day_path(date.get_year(), date.get_month(), date.get_day()); string text; if (!FileUtils.test (path, FileTest.IS_REGULAR)) text = ""; else { try { FileUtils.get_contents(path, out text); } catch (FileError e) { text = ""; } } if (i == 0 || text != "") { add_day(date, text); } date.add_days(1); } } } public class Calendar : Gtk.VBox { protected Gtk.Calendar calendar; protected Gtk.Notebook notebook; protected Gtk.Notebook day_notebook; protected FileNotes month_notes; protected FileNotes day_notes; protected FileNotes general_notes; protected Next30 next_30; protected int cur_year; protected int cur_month; protected int cur_day; public Calendar() { calendar = new Gtk.Calendar(); calendar.day_selected += on_day_selected; calendar.month_changed += on_month_changed; pack_start(calendar, false, false, 0); notebook = new Gtk.Notebook(); day_notebook = new Gtk.Notebook(); next_30 = new Next30(); next_30.selected += on_next30_selected; day_notebook.append_page(next_30, new Gtk.Label("Next 30")); day_notes = new FileNotes(); day_notebook.append_page(day_notes, new Gtk.Label("Day")); notebook.append_page(day_notebook, new Gtk.Label("Day")); day_notebook.show_tabs = false; month_notes = new FileNotes(); notebook.append_page(month_notes, new Gtk.Label("Month")); general_notes = new FileNotes(); general_notes.load(zavai.config.homedir + "/cal/notes.txt"); notebook.append_page(general_notes, new Gtk.Label("General")); pack_start(notebook, true, true, 0); on_month_changed(); on_day_selected(); } private void on_next30_selected(int year, int month, int day) { // Select this day in the calendar calendar.year = year; calendar.month = month-1; calendar.day = day; // View the day notes day_notebook.set_current_page(1); // TODO: when clicking on calendar, show next30 again } private void on_month_changed() { flush(); calendar.clear_marks(); string mpath = month_path(calendar.year, calendar.month + 1); month_notes.load(mpath + "/00.txt"); Dir dir; try { dir = Dir.open(mpath); } catch (FileError e) { zavai.log.error(e.message); return; } while (true) { var d = dir.read_name(); if (d == null) break; if (d[0].isdigit() && d.has_suffix(".txt") && d.size() == 6) { calendar.mark_day((int)d.to_ulong(null, 10)); } } } private void on_day_selected() { cur_year = calendar.year; cur_month = calendar.month + 1; cur_day = calendar.day; string path = day_path(cur_year, cur_month, cur_day); day_notes.load(path); string mpath = month_path(cur_year, cur_month); month_notes.load(mpath + "/00.txt"); Date date = Date(); date.set_dmy((DateDay)cur_day, cur_month, (DateYear)cur_year); next_30.update(date); day_notebook.set_current_page(0); } public void flush() { day_notes.save(); month_notes.save(); general_notes.save(); } public void show_today() { // Go to current date var now = Time.local(time_t()); calendar.year = now.year + 1900; calendar.month = now.month; calendar.day = now.day; on_month_changed(); } } } }