// 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 .
//
namespace Maya.Util {
int compare_events (E.CalComponent comp1, E.CalComponent comp2) {
var date1 = Util.ical_to_date_time (comp1.get_icalcomponent ().get_dtstart ());
var date2 = Util.ical_to_date_time (comp2.get_icalcomponent ().get_dtstart ());
if (date1.compare (date2) != 0)
return date1.compare(date2);
// If they have the same date, sort them alphabetically
E.CalComponentText summary1;
E.CalComponentText summary2;
comp1.get_summary (out summary1);
comp2.get_summary (out summary2);
if (summary1.value < summary2.value)
return -1;
if (summary1.value > summary2.value)
return 1;
return 0;
}
//--- Date and Time ---//
/**
* Converts two datetimes to one icaltimetype. The first contains the date,
* its time settings are ignored. The second one contains the time itself.
*/
iCal.icaltimetype date_time_to_ical (DateTime date, DateTime time) {
iCal.icaltimetype result = iCal.icaltime_from_day_of_year
(date.get_day_of_year (), date.get_year ());
result.hour = time.get_hour ();
result.minute = time.get_minute ();
result.second = time.get_second ();
return result;
}
/**
* Converts the given icaltimetype to a DateTime.
*/
DateTime ical_to_date_time (iCal.icaltimetype date) {
string tzid = date.zone.get_tzid ();
TimeZone zone = new TimeZone (tzid);
return new DateTime (zone, date.year, date.month,
date.day, date.hour, date.minute, date.second);
}
DateTime ecal_to_date_time (E.CalComponentDateTime date) {
DateTime result = new DateTime(new TimeZone.local(), date.value.year, date.value.month, date.value.day, date.value.hour, date.value.minute, date.value.second);
return result;
}
DateRange event_date_range (E.CalComponent event) {
E.CalComponentDateTime dt_start;
event.get_dtstart (out dt_start);
E.CalComponentDateTime dt_end;
event.get_dtend (out dt_end);
var start = ecal_to_date_time (dt_start);
var end = ecal_to_date_time (dt_end);
bool allday = is_the_all_day (start, end);
if (allday)
end = end.add_days (-1);
// If end is before start, switch the two
if (end.compare (start) < 0) {
var temp = end;
end = start;
start = temp;
}
return new Util.DateRange (strip_time(start), strip_time(end));
}
bool is_multiday_event (E.CalComponent event) {
return event_date_range (event).to_list() .size > 1;
}
/**
* Say if an event lasts all day.
*/
bool is_the_all_day (DateTime dtstart, DateTime dtend) {
if ((dtend.get_hour() == dtend.get_minute()) && (dtstart.get_hour() == dtend.get_hour()) && (dtstart.get_hour() == dtstart.get_minute()) && (dtend.get_hour() == 0)) {
return true;
}
else {
return false;
}
}
public DateTime get_start_of_month (owned DateTime? date = null) {
if (date==null)
date = new DateTime.now_local();
return new DateTime.local (date.get_year(), date.get_month(), 1, 0, 0, 0);
}
public DateTime strip_time (DateTime datetime) {
int y,m,d;
datetime.get_ymd (out y, out m, out d);
return new DateTime.local (y, m, d, 0, 0, 0);
}
/* Create a map interleaving DateRanges dr1 and dr2 */
public Gee.Map zip_date_ranges (DateRange dr1, DateRange dr2)
requires (dr1.days == dr2.days) {
var map = new Gee.TreeMap(
(CompareFunc) DateTime.compare,
(EqualFunc) datetime_equal_func);
var i1 = dr1.iterator();
var i2 = dr2.iterator();
while (i1.next() && i2.next()) {
map.set (i1.get(), i2.get());
}
return map;
}
/* Iterator of DateRange objects */
public class DateIterator : Object, Gee.Iterator {
DateTime current;
DateRange range;
public DateIterator (DateRange range) {
this.range = range;
this.current = range.first.add_days (-1);
}
public bool next () {
if (! has_next ())
return false;
current = this.current.add_days (1);
return true;
}
public bool has_next() {
return current.compare(range.last) < 0;
}
public bool first () {
current = range.first;
return true;
}
public new DateTime get () {
return current;
}
public void remove() {
assert_not_reached();
}
}
/* Represents date range from 'first' to 'last' inclusive */
public class DateRange : Object, Gee.Iterable {
public DateTime first { get; private set; }
public DateTime last { get; private set; }
public int64 days {
get { return last.difference(first).DAY; }
}
public DateRange (DateTime first, DateTime last) {
assert (first.compare(last)<=0);
this.first = first;
this.last = last;
}
public DateRange.copy (DateRange date_range) {
this (date_range.first, date_range.last);
}
public bool equals (DateRange other) {
return (first==other.first && last==other.last);
}
public Type element_type {
get { return typeof(DateTime); }
}
public Gee.Iterator iterator () {
return new DateIterator (this);
}
public bool contains (DateTime time) {
return (first.compare (time) < 1) && (last.compare (time) > -1);
}
public Gee.SortedSet to_set() {
var @set = new Gee.TreeSet ((CompareFunc) DateTime.compare);
foreach (var date in this)
set.add (date);
return @set;
}
public Gee.List to_list() {
var list = new Gee.ArrayList ((EqualFunc) datetime_equal_func);
foreach (var date in this)
list.add (date);
return list;
}
}
// /* Convert E.CalComponentDateTime to GLib.DateTime */
// public DateTime convert_to_datetime (E.CalComponentDateTime dt) {
//
// unowned iCal.icaltimetype idt = dt.value;
// var tz = new TimeZone (dt.tzid);
//
// return new DateTime(tz, idt.year, idt.month, idt.day, idt.hour, idt.minute, idt.second);
// }
//--- Gee Utility Functions ---//
/* Interleaves the values of two collections into a Map */
public void zip (Gee.Iterable iterable1, Gee.Iterable iterable2, ref Gee.Map map) {
var i1 = iterable1.iterator();
var i2 = iterable2.iterator();
while (i1.next() && i2.next())
map.set (i1, i2);
}
/* Constructs a new set with keys equal to the values of keymap */
public void remap (Gee.Map keymap, Gee.Map valmap, ref Gee.Map remap) {
foreach (K key in valmap) {
var k = keymap [key];
var v = valmap [key];
remap.set (k, v);
}
}
/* Computes hash value for string */
public uint string_hash_func (string key) {
return key.hash();
}
/* Computes hash value for DateTime */
public uint datetime_hash_func (DateTime key) {
return key.hash();
}
/* Computes hash value for E.CalComponent */
public uint calcomponent_hash_func (E.CalComponent key) {
string uid;
key.get_uid (out uid);
return str_hash (uid);
}
/* Computes hash value for E.Source */
public uint source_hash_func (E.Source key) {
return str_hash (key.peek_uid());
}
/* Computes hash value for E.SourceGroup */
public uint source_group_hash_func (E.SourceGroup key) {
return str_hash (key.peek_uid());
}
/* Returns true if 'a' and 'b' are the same string */
public bool string_equal_func (string a, string b) {
return a == b;
}
/* Returns true if 'a' and 'b' are the same GLib.DateTime */
public bool datetime_equal_func (DateTime a, DateTime b) {
return a.equal (b);
}
/* Returns true if 'a' and 'b' are the same E.SourceGroup */
public bool source_group_equal_func (E.SourceGroup a, E.SourceGroup b) {
return a.peek_uid() == b.peek_uid();
}
/* Returns true if 'a' and 'b' are the same E.CalComponent */
public bool calcomponent_equal_func (E.CalComponent a, E.CalComponent b) {
string uid_a, uid_b;
a.get_uid (out uid_a);
b.get_uid (out uid_b);
return uid_a == uid_b;
}
/* Returns true if 'a' and 'b' are the same E.Source */
public bool source_equal_func (E.Source a, E.Source b) {
return a.peek_uid() == b.peek_uid();
}
//--- TreeModel Utility Functions ---//
public Gtk.TreePath? find_treemodel_object (Gtk.TreeModel model, int column, T object, EqualFunc? eqfunc=null) {
Gtk.TreePath? path = null;
model.foreach( (m, p, iter) => {
Value gvalue;
model.get_value (iter, column, out gvalue);
T ovalue = gvalue.get_object();
if ( (eqfunc == null && ovalue == object)
|| (eqfunc != null && eqfunc(ovalue, object))) {
path = p;
return true;
}
return false;
});
return path;
}
//--- Gtk Miscellaneous ---//
public class Css {
private static Gtk.CssProvider? _css_provider;
// Retrieve global css provider
public static Gtk.CssProvider get_css_provider () {
if (_css_provider == null) {
_css_provider = new Gtk.CssProvider ();
try {
_css_provider.load_from_path (Build.PKGDATADIR + "/style/default.css");
} catch (Error e) {
warning ("Could not add css provider. Some widgets will not look as intended. %s", e.message);
}
}
return _css_provider;
}
}
public Gtk.Widget set_margins (Gtk.Widget widget, int top, int right, int bottom, int left) {
widget.margin_top = top;
widget.margin_right = right;
widget.margin_bottom = bottom;
widget.margin_left = left;
return widget;
}
public Gtk.Alignment set_paddings (Gtk.Widget widget, int top, int right, int bottom, int left) {
var alignment = new Gtk.Alignment (0.0f, 0.0f, 1.0f, 1.0f);
alignment.top_padding = top;
alignment.right_padding = right;
alignment.bottom_padding = bottom;
alignment.left_padding = left;
alignment.add (widget);
return alignment;
}
//--- ical Exportation ---//
/**
* Export all the selected calendars to a temporary ical file
* TODO : The code can surely be optimised, it is just a first try.
*/
public void save_temp_selected_calendars (){
var sourcemagr = new Model.SourceManager ();
var calmodel = new Model.CalendarModel(sourcemagr, Maya.Settings.Weekday.MONDAY);
var path = GLib.Environment.get_tmp_dir () + "/calendar.ics";
string output = "BEGIN:VCALENDAR
VERSION:2.0
PRODID:http://www.elementaryos.org/
METHOD:PUBLISH\n";
foreach (var source in sourcemagr.get_enabled_sources ()) {
try {
var client = new E.CalClient(source, E.CalClientSourceType.EVENTS);
var iso_first = E.isodate_from_time_t((ulong) calmodel.data_range.first.to_unix());
var iso_last = E.isodate_from_time_t((ulong) calmodel.data_range.last.to_unix());
var query = @"(occur-in-time-range? (make-time \"$iso_first\") (make-time \"$iso_last\"))";
GLib.SList icalcomps;
client.get_object_list_sync(query, out icalcomps, null);
foreach (var icalcomp in icalcomps) {
assert (icalcomp != null);
output = output + icalcomp.as_ical_string ();
}
} catch (GLib.Error e) {
warning (e.message);
}
}
try {
GLib.File file = GLib.File.new_for_path (path);
output = output + "END:VCALENDAR";
uint8[] data = output.data;
string s;
file.replace_contents (data, null, false, 0, out s);
} catch (GLib.Error e){
warning (e.message);
}
}
}